1 /*
2 * UAE - The Un*x Amiga Emulator - CPU core
3 *
4 * MC68000 emulation
5 *
6 * (c) 1995 Bernd Schmidt
7 *
8 * Adaptation to Hatari by Thomas Huth
9 *
10 * This file is distributed under the GNU General Public License, version 2
11 * or at your option any later version. Read the file gpl.txt for details.
12 */
13
14
15 /* 2007/11/12 [NP] Add HATARI_TRACE_CPU_DISASM. */
16 /* 2007/11/15 [NP] In MakeFromSR, writes to m and t0 should be ignored and set to 0 if cpu < 68020 */
17 /* 2007/11/26 [NP] We set BusErrorPC in m68k_run_1 instead of M68000_BusError, else the BusErrorPC */
18 /* will not point to the opcode that generated the bus error. */
19 /* Huge debug/work on Exceptions 2/3 stack frames, result is more accurate and */
20 /* allow to pass the very tricky Transbeauce 2 Demo's protection. */
21 /* 2007/11/28 [NP] Backport DIVS/DIVU cycles exact routines from WinUAE (original work by Jorge */
22 /* Cwik, pasti@fxatari.com). */
23 /* 2007/12/06 [NP] The PC stored in the stack frame for the bus error is complex to emulate, */
24 /* because it doesn't necessarily point to the next instruction after the one that */
25 /* triggered the bus error. In the case of the Transbeauce 2 Demo, after */
26 /* 'move.l $0.w,$24.w', PC is incremented of 4 bytes, not 6, and stored in the */
27 /* stack. Special case to decrement PC of 2 bytes if opcode is '21f8'. */
28 /* This should be fixed with a real model. */
29 /* 2007/12/07 [NP] If Trace is enabled and a group 2 exception occurs (such as CHK), the trace */
30 /* handler should be called after the group 2's handler. If a bus error, address */
31 /* error or illegal occurs while Trace is enabled, the trace handler should not be */
32 /* called after this instruction (Transbeauce 2 Demo, Phaleon Demo). */
33 /* This means that if a CHK is executed while trace bit was set, we must set PC */
34 /* to CHK handler, turn trace off in the internal SR, but we must still call the */
35 /* trace handler one last time with the PC set to the CHK's handler (even if */
36 /* trace mode is internally turned off while processing an exception). Once trace */
37 /* handler is finished (RTE), we return to the CHK's handler. */
38 /* This is true for DIV BY 0, CHK, TRAPV and TRAP. */
39 /* Backport exception_trace() from WinUAE to handle this behaviour (used in */
40 /* Transbeauce 2 demo). */
41 /* 2007/12/09 [NP] 'dc.w $a' should not be used to call 'OpCode_SysInit' but should give an illegal*/
42 /* instruction (Transbeauce 2 demo). */
43 /* Instead of always replacing the illegal instructions $8, $a and $c by the */
44 /* 3 functions required for HD emulation, we now do it in cart.c only if the */
45 /* built-in cartridge image is loaded. */
46 /* YEAH! Hatari is now the first emulator to pass the Transbeauce 2 protection :) */
47 /* 2007/12/18 [NP] More precise timings for HBL, VBL and MFP interrupts. On ST, these interrupts */
48 /* are taking 56 cycles instead of the 44 cycles in the 68000's documentation. */
49 /* 2007/12/24 [NP] If an interrupt (HBL, VBL) is pending after instruction 'n' was processed, the */
50 /* exception should be called before instr. 'n+1' is processed, not after (else the*/
51 /* interrupt's handler is delayed by one 68000's instruction, which could break */
52 /* some demos with too strict timings) (ACF's Demo Main Menu). */
53 /* We call the interrupt if ( SPCFLAG_INT | SPCFLAG_DOINT ) is set, not only if */
54 /* SPCFLAG_DOINT is set (as it was already the case when handling 'STOP'). */
55 /* 2007/12/25 [NP] FIXME When handling exceptions' cycles, using nr >= 64 to determine if this is */
56 /* an MFP exception could be wrong if the MFP VR was set to another value than the */
57 /* default $40 (this could be a problem with programs requiring a precise cycles */
58 /* calculation while changing VR, but no such programs were encountered so far). */
59 /* -> FIXED, see 2008/10/05 */
60 /* 2008/04/17 [NP] In m68k_run_1/m68k_run_2, add the wait state cycles before testing if content */
61 /* of PendingInterruptCount is <= 0 (else the int could happen a few cycles earlier*/
62 /* than expected in some rare cases (reading $fffa21 in BIG Demo Screen 1)). */
63 /* 2008/09/14 [NP] Add the value of the new PC in the exception's log. */
64 /* 2008/09/14 [NP] Correct cycles for TRAP are 34 not 38 (4 more cycles were counted because cpuemu*/
65 /* returns 4 and Exception() adds 34) (Phaleon / Illusion Demo by Next). */
66 /* FIXME : Others exception cycles may be wrong too. */
67 /* 2008/10/05 [NP] Add a parameter 'ExceptionSource' to Exception(). This allows to know the source*/
68 /* of the exception (video, mfp, cpu) and properly handle MFP interrupts. Since */
69 /* it's possible to change the vector base in $fffa17, MFP int vectors can overlap */
70 /* the 'normal' 68000 ones and the exception number is not enough to decide. */
71 /* We need ExceptionSource to remove the ambiguity. */
72 /* Fix High Fidelity Dreams by Aura which sets MFP vector base to $c0 instead of */
73 /* $100. In that case, timer B int becomes exception nr 56 and conflicts with the */
74 /* 'MMU config error' exception, which takes 4 cycles instead of 56 cycles for MFP.*/
75 /* 2008/11/18 [NP] In 'do_specialties()', when the cpu is in the STOP state, we must test all */
76 /* possible int handlers while PendingInterruptCount <= 0 without increasing the */
77 /* cpu cycle counter. In the case where both an MFP int and an HBL occur at the */
78 /* same time for example, the HBL was delayed by 4 cycles if no MFP exception */
79 /* was triggered, which was wrong (this happened mainly with the TOS timer D that */
80 /* expires very often). Such precision is required for very recent hardscroll */
81 /* techniques that use 'stop' to stay in sync with the video shifter. */
82 /* 2008/11/23 [NP] In 'do_specialties()', when in STOP state, we must first test for a pending */
83 /* interrupt that would exit the STOP state immediately, without doing a 'while' */
84 /* loop until 'SPCFLAG_INT' or 'SPCFLAG_DOINT' are set. */
85 /* 2008/11/29 [NP] Call 'InterruptAddJitter()' when a video interrupt happens to precisely emulate */
86 /* the jitter happening on the Atari (see video.c for the jitter patterns). */
87 /* FIXME : Pattern is not always correct when handling pending interrupt in STOP */
88 /* state, but this should be harmless as no program has been found using this. */
89 /* 2008/12/05 [NP] On Atari it takes 56 cycles to process an interrupt. During that time, a higher */
90 /* level interrupt could happen and we must execute it before the previous int */
91 /* (see m68k_run_1()). */
92 /* This is the case for the VBL which can interrupt the last HBL of a screen */
93 /* (end of line 312) at various point (from 0 to 8 cycles). */
94 /* This fixes the fullscreen tunnel in Suretrip 49% by Checkpoint, which uses a */
95 /* really buggy vbl/hbl combination, even on a real ST. Also fixes sample sound */
96 /* in Swedish New Year's TCB screen. */
97 /* 2008/12/11 [NP] Extract interrupt handling from do_specialties() in do_specialties_interrupt() */
98 /* and factorize some code. In m68k_run_1 when testing for multiple interrupts at */
99 /* the same time, call do_specialties_interrupt() to check only the special flags */
100 /* related to interrupts (MFP and video) (else, this caused problem when the TRACE */
101 /* flag was set). */
102 /* 2008/12/14 [NP] In m68k_run_1(), we should check for simultaneous ints only if the cpu is not */
103 /* in the STOP state after the last instruction was executed. Else, the call to */
104 /* do_specialties_interrupt() could acknowledge the interrupt and we would never */
105 /* exit the STOP state in do_specialties() just after (the problem can happen if */
106 /* the TOS timer D expires just at the same time as the STOP instruction). */
107 /* Fix regression since 2008/12/11 in the hidden screen from ULM in Oh Crickey... */
108 /* 2008/12/20 [NP] In m68k_run_1(), when checking interrupts and STOP mode, we should test */
109 /* PendingInterruptCount before regs.spcflags to have a faster evaluation of the */
110 /* 'while' condition (PendingInterruptCount <= 0 is true less often than STOP==0) */
111 /* 2011/04/29 [NP] In Exception(), check the new PC is not on odd address ; raise an address error */
112 /* exception if it's the case. */
113 /* 2012/09/01 [NP] Add a special case to correct the stacked PC when a bus error happens during */
114 /* a movem (fix the game Blood Money). */
115 /* 2013/03/16 [NP] In refill_prefetch(), reload only one new word in regs.prefetch if low word is */
116 /* still valid : low word goes to high word and we reload only low word */
117 /* (fix EOR/ADD self modified code in the protection for the game Damocles). */
118 /* 2013/04/11 [NP] In Exception(), call MFP_ProcessIACK after 12 cycles to update the MFP's vector */
119 /* number used for the exception (see mfp.c). */
120 /* 2013/05/03 [NP] In Exception(), handle IACK for HBL and VBL interrupts too, allowing pending bit*/
121 /* to be set twice during an active video interrupt (correct fix for Super Monaco */
122 /* GP, Super Hang On, Monster Business, European Demo's Intro, BBC Menu 52). */
123 /* 2014/02/22 [NP] In Exception(), call valid_address() before reading the opcode at BusErrorPC, */
124 /* else this will cause an unwanted "double bus error" ("Union Demo" loader). */
125 /* 2014/02/22 [NP] In refill_prefetch(), use get_word() instead of do_get_mem_word() to generate */
126 /* a bus error when trying to read from an invalid region. */
127 /* 2014/03/18 [NP] In Exception(), add a specific case to restore the dest part of a "move" after */
128 /* it was overwritten during a bus error (fix the game Dragon Flight). */
129 /* 2014/04/06 [NP] In Exception(), add a special case for last_addr_for_exception_3 stored in the */
130 /* stack after a bus error (fix the game Batman The Movie). */
131 /* 2014/09/07 [NP] In m68k_run_1(), if get_iword_prefetch() triggers a bus error, we must call the */
132 /* bus error immediately and fetch the correct opcode for the bus error handler */
133 /* (fix Blood Money on Superior 65, PC=4e664e66 after RTS). */
134 /* 2014/09/07 [NP] For address error, store if the access was in cpu space or data space and fix */
135 /* the exception stack frame accordingly (fix Blood Money on Superior 65, */
136 /* PC=4e664e66 after RTS) */
137 /* 2015/02/11 [NP] Replace BusErrorPC by regs.instruction_pc, to get similar code to WinUAE's cpu */
138
139
140 const char NewCpu_fileid[] = "Hatari newcpu.c : " __DATE__ " " __TIME__;
141
142 #include "sysdeps.h"
143 #include "hatari-glue.h"
144 #include "maccess.h"
145 #include "memory.h"
146 #include "newcpu.h"
147 #include "main.h"
148 #include "m68000.h"
149 #include "reset.h"
150 #include "cycInt.h"
151 #include "mfp.h"
152 #include "tos.h"
153 #include "vdi.h"
154 #include "cart.h"
155 #include "dialog.h"
156 #include "bios.h"
157 #include "xbios.h"
158 #include "screen.h"
159 #include "video.h"
160 #include "options.h"
161 #include "dsp.h"
162 #include "log.h"
163 #include "debugui.h"
164 #include "debugcpu.h"
165 #include "68kDisass.h"
166 #include "stMemory.h"
167
168 #ifdef HAVE_CAPSIMAGE
169 #if CAPSIMAGE_VERSION == 5
170 #include <caps5/CapsLibAll.h>
171 #endif
172 #endif
173
174 //#define DEBUG_PREFETCH
175
176 struct flag_struct regflags;
177
178 /* Opcode of faulting instruction */
179 uae_u16 last_op_for_exception_3;
180 /* PC at fault time */
181 uaecptr last_addr_for_exception_3;
182 /* Address that generated the exception */
183 uaecptr last_fault_for_exception_3;
184 /* read (0) or write (1) access */
185 int last_writeaccess_for_exception_3;
186 /* instruction (1) or data (0) access */
187 int last_instructionaccess_for_exception_3;
188
189 const int areg_byteinc[] = { 1,1,1,1,1,1,1,2 };
190 const int imm8_table[] = { 8,1,2,3,4,5,6,7 };
191
192 int movem_index1[256];
193 int movem_index2[256];
194 int movem_next[256];
195
196 int fpp_movem_index1[256];
197 int fpp_movem_index2[256];
198 int fpp_movem_next[256];
199
200 cpuop_func *cpufunctbl[65536];
201
202 int OpcodeFamily;
203 int BusCyclePenalty = 0;
204
205 #define COUNT_INSTRS 0
206
207 #if COUNT_INSTRS
208 static unsigned long int instrcount[65536];
209 static uae_u16 opcodenums[65536];
210
compfn(const void * el1,const void * el2)211 static int compfn (const void *el1, const void *el2)
212 {
213 return instrcount[*(const uae_u16 *)el1] < instrcount[*(const uae_u16 *)el2];
214 }
215
icountfilename(void)216 static char *icountfilename (void)
217 {
218 char *name = getenv ("INSNCOUNT");
219 if (name)
220 return name;
221 return COUNT_INSTRS == 2 ? "frequent.68k" : "insncount";
222 }
223
dump_counts(void)224 void dump_counts (void)
225 {
226 FILE *f = fopen (icountfilename (), "w");
227 unsigned long int total;
228 int i;
229
230 write_log ("Writing instruction count file...\n");
231 for (i = 0; i < 65536; i++) {
232 opcodenums[i] = i;
233 total += instrcount[i];
234 }
235 qsort (opcodenums, 65536, sizeof(uae_u16), compfn);
236
237 fprintf (f, "Total: %lu\n", total);
238 for (i=0; i < 65536; i++) {
239 unsigned long int cnt = instrcount[opcodenums[i]];
240 struct instr *dp;
241 struct mnemolookup *lookup;
242 if (!cnt)
243 break;
244 dp = table68k + opcodenums[i];
245 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
246 ;
247 fprintf (f, "%04x: %lu %s\n", opcodenums[i], cnt, lookup->name);
248 }
249 fclose (f);
250 }
251 #else
dump_counts(void)252 void dump_counts (void)
253 {
254 }
255 #endif
256
cpu_halt(void)257 static void cpu_halt ( void )
258 {
259 Dialog_HaltDlg();
260 }
261
262
263 static unsigned long op_illg_1 (uae_u32 opcode) REGPARAM;
264
op_illg_1(uae_u32 opcode)265 static unsigned long REGPARAM2 op_illg_1 (uae_u32 opcode)
266 {
267 op_illg (opcode);
268 return 4;
269 }
270
271
build_cpufunctbl(void)272 void build_cpufunctbl(void)
273 {
274 int i;
275 unsigned long opcode;
276 const struct cputbl *tbl = (currprefs.cpu_level == 4 ? op_smalltbl_0_ff
277 : currprefs.cpu_level == 3 ? op_smalltbl_1_ff
278 : currprefs.cpu_level == 2 ? op_smalltbl_2_ff
279 : currprefs.cpu_level == 1 ? op_smalltbl_3_ff
280 : ! currprefs.cpu_compatible ? op_smalltbl_4_ff
281 : op_smalltbl_5_ff);
282
283 Log_Printf(LOG_DEBUG, "Building CPU function table (%d %d %d).\n",
284 currprefs.cpu_level, currprefs.cpu_compatible, currprefs.address_space_24);
285
286 for (opcode = 0; opcode < 65536; opcode++)
287 cpufunctbl[opcode] = op_illg_1;
288 for (i = 0; tbl[i].handler != NULL; i++) {
289 if (! tbl[i].specific)
290 cpufunctbl[tbl[i].opcode] = tbl[i].handler;
291 }
292 for (opcode = 0; opcode < 65536; opcode++) {
293 cpuop_func *f;
294
295 if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > currprefs.cpu_level)
296 continue;
297
298 if (table68k[opcode].handler != -1) {
299 f = cpufunctbl[table68k[opcode].handler];
300 if (f == op_illg_1)
301 abort();
302 cpufunctbl[opcode] = f;
303 }
304 }
305 for (i = 0; tbl[i].handler != NULL; i++) {
306 if (tbl[i].specific)
307 cpufunctbl[tbl[i].opcode] = tbl[i].handler;
308 }
309 }
310
311
312
init_m68k(void)313 void init_m68k (void)
314 {
315 int i;
316
317 for (i = 0 ; i < 256 ; i++) {
318 int j;
319 for (j = 0 ; j < 8 ; j++) {
320 if (i & (1 << j)) break;
321 }
322 movem_index1[i] = j;
323 movem_index2[i] = 7-j;
324 movem_next[i] = i & (~(1 << j));
325 }
326 for (i = 0 ; i < 256 ; i++) {
327 int j;
328 for (j = 7 ; j >= 0 ; j--) {
329 if (i & (1 << j)) break;
330 }
331 fpp_movem_index1[i] = 7-j;
332 fpp_movem_index2[i] = j;
333 fpp_movem_next[i] = i & (~(1 << j));
334 }
335 #if COUNT_INSTRS
336 {
337 FILE *f = fopen (icountfilename (), "r");
338 memset (instrcount, 0, sizeof instrcount);
339 if (f) {
340 uae_u32 opcode, count, total;
341 char name[20];
342 write_log ("Reading instruction count file...\n");
343 fscanf (f, "Total: %lu\n", &total);
344 while (fscanf (f, "%lx: %lu %s\n", &opcode, &count, name) == 3) {
345 instrcount[opcode] = count;
346 }
347 fclose(f);
348 }
349 }
350 #endif
351 write_log ("Building CPU table for configuration: 68");
352 if (currprefs.address_space_24 && currprefs.cpu_level > 1)
353 write_log ("EC");
354 switch (currprefs.cpu_level) {
355 case 1:
356 write_log ("010");
357 break;
358 case 2:
359 write_log ("020");
360 break;
361 case 3:
362 write_log ("020/881");
363 break;
364 case 4:
365 /* Who is going to miss the MMU anyway...? :-) */
366 write_log ("040");
367 break;
368 default:
369 write_log ("000");
370 break;
371 }
372 if (currprefs.cpu_compatible)
373 write_log (" (compatible mode)");
374 write_log ("\n");
375
376 read_table68k ();
377 do_merges ();
378
379 Log_Printf(LOG_DEBUG, "%d CPU functions\n", nr_cpuop_funcs);
380
381 build_cpufunctbl ();
382 }
383
384
385 /* not used ATM:
386 static struct regstruct regs_backup[16];
387 static int backup_pointer = 0;
388 struct regstruct lastint_regs;
389 int lastint_no;
390 */
391 struct regstruct regs;
392 static long int m68kpc_offset;
393
394
395 #define get_ibyte_1(o) STMemory_ReadByte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1)
396 #define get_iword_1(o) STMemory_ReadWord(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
397 #define get_ilong_1(o) STMemory_ReadLong(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
398
ShowEA(FILE * f,int reg,amodes mode,wordsizes size,char * buf)399 uae_s32 ShowEA (FILE *f, int reg, amodes mode, wordsizes size, char *buf)
400 {
401 uae_u16 dp;
402 uae_s8 disp8;
403 uae_s16 disp16;
404 int r;
405 uae_u32 dispreg;
406 uaecptr addr;
407 uae_s32 offset = 0;
408 char buffer[80];
409
410 switch (mode){
411 case Dreg:
412 sprintf (buffer,"D%d", reg);
413 break;
414 case Areg:
415 sprintf (buffer,"A%d", reg);
416 break;
417 case Aind:
418 sprintf (buffer,"(A%d)", reg);
419 break;
420 case Aipi:
421 sprintf (buffer,"(A%d)+", reg);
422 break;
423 case Apdi:
424 sprintf (buffer,"-(A%d)", reg);
425 break;
426 case Ad16:
427 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
428 addr = m68k_areg(regs,reg) + (uae_s16)disp16;
429 sprintf (buffer,"(A%d,$%04x) == $%08lx", reg, disp16 & 0xffff,
430 (unsigned long)addr);
431 break;
432 case Ad8r:
433 dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
434 disp8 = dp & 0xFF;
435 r = (dp & 0x7000) >> 12;
436 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
437 if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
438 dispreg <<= (dp >> 9) & 3;
439
440 if (dp & 0x100) {
441 uae_s32 outer = 0, disp = 0;
442 uae_s32 base = m68k_areg(regs,reg);
443 char name[10];
444 sprintf (name,"A%d, ",reg);
445 if (dp & 0x80) { base = 0; name[0] = 0; }
446 if (dp & 0x40) dispreg = 0;
447 if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
448 if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
449 base += disp;
450
451 if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
452 if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
453
454 if (!(dp & 4)) base += dispreg;
455 if (dp & 3) base = get_long (base);
456 if (dp & 4) base += dispreg;
457
458 addr = base + outer;
459 sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
460 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
461 1 << ((dp >> 9) & 3),
462 (long)disp, (long)outer, (unsigned long)addr);
463 } else {
464 addr = m68k_areg(regs,reg) + (uae_s32)((uae_s8)disp8) + dispreg;
465 sprintf (buffer,"(A%d, %c%d.%c*%d, $%02x) == $%08lx", reg,
466 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
467 1 << ((dp >> 9) & 3), disp8,
468 (unsigned long)addr);
469 }
470 break;
471 case PC16:
472 addr = m68k_getpc () + m68kpc_offset;
473 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
474 addr += (uae_s16)disp16;
475 sprintf (buffer,"(PC,$%04x) == $%08lx", disp16 & 0xffff,(unsigned long)addr);
476 break;
477 case PC8r:
478 addr = m68k_getpc () + m68kpc_offset;
479 dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
480 disp8 = dp & 0xFF;
481 r = (dp & 0x7000) >> 12;
482 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
483 if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
484 dispreg <<= (dp >> 9) & 3;
485
486 if (dp & 0x100) {
487 uae_s32 outer = 0,disp = 0;
488 uae_s32 base = addr;
489 char name[10];
490 sprintf (name,"PC, ");
491 if (dp & 0x80) { base = 0; name[0] = 0; }
492 if (dp & 0x40) dispreg = 0;
493 if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
494 if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
495 base += disp;
496
497 if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
498 if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
499
500 if (!(dp & 4)) base += dispreg;
501 if (dp & 3) base = get_long (base);
502 if (dp & 4) base += dispreg;
503
504 addr = base + outer;
505 sprintf (buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%08lx", name,
506 dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
507 1 << ((dp >> 9) & 3),
508 (long)disp, (long)outer, (unsigned long)addr);
509 } else {
510 addr += (uae_s32)((uae_s8)disp8) + dispreg;
511 sprintf (buffer,"(PC, %c%d.%c*%d, $%02x) == $%08lx", dp & 0x8000 ? 'A' : 'D',
512 (int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3),
513 disp8, (unsigned long)addr);
514 }
515 break;
516 case absw:
517 sprintf (buffer,"$%08lx", (unsigned long)(uae_s32)(uae_s16)get_iword_1 (m68kpc_offset));
518 m68kpc_offset += 2;
519 break;
520 case absl:
521 sprintf (buffer,"$%08lx", (unsigned long)get_ilong_1 (m68kpc_offset));
522 m68kpc_offset += 4;
523 break;
524 case imm:
525 switch (size){
526 case sz_byte:
527 sprintf (buffer,"#$%02x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xff));
528 m68kpc_offset += 2;
529 break;
530 case sz_word:
531 sprintf (buffer,"#$%04x", (unsigned int)(get_iword_1 (m68kpc_offset) & 0xffff));
532 m68kpc_offset += 2;
533 break;
534 case sz_long:
535 sprintf (buffer,"#$%08lx", (unsigned long)(get_ilong_1 (m68kpc_offset)));
536 m68kpc_offset += 4;
537 break;
538 default:
539 break;
540 }
541 break;
542 case imm0:
543 offset = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
544 m68kpc_offset += 2;
545 sprintf (buffer,"#$%02x", (unsigned int)(offset & 0xff));
546 break;
547 case imm1:
548 offset = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
549 m68kpc_offset += 2;
550 sprintf (buffer,"#$%04x", (unsigned int)(offset & 0xffff));
551 break;
552 case imm2:
553 offset = (uae_s32)get_ilong_1 (m68kpc_offset);
554 m68kpc_offset += 4;
555 sprintf (buffer,"#$%08lx", (unsigned long)offset);
556 break;
557 case immi:
558 offset = (uae_s32)(uae_s8)(reg & 0xff);
559 sprintf (buffer,"#$%08lx", (unsigned long)offset);
560 break;
561 default:
562 break;
563 }
564 if (buf == 0)
565 fprintf (f, "%s", buffer);
566 else
567 strcat (buf, buffer);
568 return offset;
569 }
570
571
572 /* The plan is that this will take over the job of exception 3 handling -
573 * the CPU emulation functions will just do a longjmp to m68k_go whenever
574 * they hit an odd address. */
575 #if 0
576 static int verify_ea (int reg, amodes mode, wordsizes size, uae_u32 *val)
577 {
578 uae_u16 dp;
579 uae_s8 disp8;
580 uae_s16 disp16;
581 int r;
582 uae_u32 dispreg;
583 uaecptr addr;
584 /*uae_s32 offset = 0;*/
585
586 switch (mode){
587 case Dreg:
588 *val = m68k_dreg (regs, reg);
589 return 1;
590 case Areg:
591 *val = m68k_areg (regs, reg);
592 return 1;
593
594 case Aind:
595 case Aipi:
596 addr = m68k_areg (regs, reg);
597 break;
598 case Apdi:
599 addr = m68k_areg (regs, reg);
600 break;
601 case Ad16:
602 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
603 addr = m68k_areg(regs,reg) + (uae_s16)disp16;
604 break;
605 case Ad8r:
606 addr = m68k_areg (regs, reg);
607 d8r_common:
608 dp = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
609 disp8 = dp & 0xFF;
610 r = (dp & 0x7000) >> 12;
611 dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
612 if (!(dp & 0x800)) dispreg = (uae_s32)(uae_s16)(dispreg);
613 dispreg <<= (dp >> 9) & 3;
614
615 if (dp & 0x100) {
616 uae_s32 outer = 0, disp = 0;
617 uae_s32 base = addr;
618 if (dp & 0x80) base = 0;
619 if (dp & 0x40) dispreg = 0;
620 if ((dp & 0x30) == 0x20) { disp = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
621 if ((dp & 0x30) == 0x30) { disp = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
622 base += disp;
623
624 if ((dp & 0x3) == 0x2) { outer = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset); m68kpc_offset += 2; }
625 if ((dp & 0x3) == 0x3) { outer = get_ilong_1 (m68kpc_offset); m68kpc_offset += 4; }
626
627 if (!(dp & 4)) base += dispreg;
628 if (dp & 3) base = get_long (base);
629 if (dp & 4) base += dispreg;
630
631 addr = base + outer;
632 } else {
633 addr += (uae_s32)((uae_s8)disp8) + dispreg;
634 }
635 break;
636 case PC16:
637 addr = m68k_getpc () + m68kpc_offset;
638 disp16 = get_iword_1 (m68kpc_offset); m68kpc_offset += 2;
639 addr += (uae_s16)disp16;
640 break;
641 case PC8r:
642 addr = m68k_getpc () + m68kpc_offset;
643 goto d8r_common;
644 case absw:
645 addr = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
646 m68kpc_offset += 2;
647 break;
648 case absl:
649 addr = get_ilong_1 (m68kpc_offset);
650 m68kpc_offset += 4;
651 break;
652 case imm:
653 switch (size){
654 case sz_byte:
655 *val = get_iword_1 (m68kpc_offset) & 0xff;
656 m68kpc_offset += 2;
657 break;
658 case sz_word:
659 *val = get_iword_1 (m68kpc_offset) & 0xffff;
660 m68kpc_offset += 2;
661 break;
662 case sz_long:
663 *val = get_ilong_1 (m68kpc_offset);
664 m68kpc_offset += 4;
665 break;
666 default:
667 break;
668 }
669 return 1;
670 case imm0:
671 *val = (uae_s32)(uae_s8)get_iword_1 (m68kpc_offset);
672 m68kpc_offset += 2;
673 return 1;
674 case imm1:
675 *val = (uae_s32)(uae_s16)get_iword_1 (m68kpc_offset);
676 m68kpc_offset += 2;
677 return 1;
678 case imm2:
679 *val = get_ilong_1 (m68kpc_offset);
680 m68kpc_offset += 4;
681 return 1;
682 case immi:
683 *val = (uae_s32)(uae_s8)(reg & 0xff);
684 return 1;
685 default:
686 addr = 0;
687 break;
688 }
689 if ((addr & 1) == 0)
690 return 1;
691
692 last_addr_for_exception_3 = m68k_getpc () + m68kpc_offset;
693 last_fault_for_exception_3 = addr;
694 return 0;
695 }
696 #endif
697
698
get_disp_ea_020(uae_u32 base,uae_u32 dp)699 uae_u32 get_disp_ea_020 (uae_u32 base, uae_u32 dp)
700 {
701 int reg = (dp >> 12) & 15;
702 uae_s32 regd = regs.regs[reg];
703 if ((dp & 0x800) == 0)
704 regd = (uae_s32)(uae_s16)regd;
705 regd <<= (dp >> 9) & 3;
706 if (dp & 0x100) {
707 uae_s32 outer = 0;
708 if (dp & 0x80) base = 0;
709 if (dp & 0x40) regd = 0;
710
711 if ((dp & 0x30) == 0x20) base += (uae_s32)(uae_s16)next_iword();
712 if ((dp & 0x30) == 0x30) base += next_ilong();
713
714 if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)next_iword();
715 if ((dp & 0x3) == 0x3) outer = next_ilong();
716
717 if ((dp & 0x4) == 0) base += regd;
718 if (dp & 0x3) base = get_long (base);
719 if (dp & 0x4) base += regd;
720
721 return base + outer;
722 } else {
723 return base + (uae_s32)((uae_s8)dp) + regd;
724 }
725 }
726
get_disp_ea_000(uae_u32 base,uae_u32 dp)727 uae_u32 get_disp_ea_000 (uae_u32 base, uae_u32 dp)
728 {
729 int reg = (dp >> 12) & 15;
730 uae_s32 regd = regs.regs[reg];
731 #if 1
732 if ((dp & 0x800) == 0)
733 regd = (uae_s32)(uae_s16)regd;
734 return base + (uae_s8)dp + regd;
735 #else
736 /* Branch-free code... benchmark this again now that
737 * things are no longer inline. */
738 uae_s32 regd16;
739 uae_u32 mask;
740 mask = ((dp & 0x800) >> 11) - 1;
741 regd16 = (uae_s32)(uae_s16)regd;
742 regd16 &= mask;
743 mask = ~mask;
744 base += (uae_s8)dp;
745 regd &= mask;
746 regd |= regd16;
747 return base + regd;
748 #endif
749 }
750
751
752 /* Create the Status Register from the flags */
MakeSR(void)753 void MakeSR (void)
754 {
755 #if 0
756 assert((regs.t1 & 1) == regs.t1);
757 assert((regs.t0 & 1) == regs.t0);
758 assert((regs.s & 1) == regs.s);
759 assert((regs.m & 1) == regs.m);
760 assert((XFLG & 1) == XFLG);
761 assert((NFLG & 1) == NFLG);
762 assert((ZFLG & 1) == ZFLG);
763 assert((VFLG & 1) == VFLG);
764 assert((CFLG & 1) == CFLG);
765 #endif
766 regs.sr = ((regs.t1 << 15) | (regs.t0 << 14)
767 | (regs.s << 13) | (regs.m << 12) | (regs.intmask << 8)
768 | (GET_XFLG << 4) | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1)
769 | GET_CFLG);
770 }
771
772
773 /* Set up the flags from Status Register */
MakeFromSR(void)774 void MakeFromSR (void)
775 {
776 int oldm = regs.m;
777 int olds = regs.s;
778
779 regs.t1 = (regs.sr >> 15) & 1;
780 regs.t0 = (regs.sr >> 14) & 1;
781 regs.s = (regs.sr >> 13) & 1;
782 regs.m = (regs.sr >> 12) & 1;
783 regs.intmask = (regs.sr >> 8) & 7;
784 SET_XFLG ((regs.sr >> 4) & 1);
785 SET_NFLG ((regs.sr >> 3) & 1);
786 SET_ZFLG ((regs.sr >> 2) & 1);
787 SET_VFLG ((regs.sr >> 1) & 1);
788 SET_CFLG (regs.sr & 1);
789 if (currprefs.cpu_level >= 2) {
790 if (olds != regs.s) {
791 if (olds) {
792 if (oldm)
793 regs.msp = m68k_areg(regs, 7);
794 else
795 regs.isp = m68k_areg(regs, 7);
796 m68k_areg(regs, 7) = regs.usp;
797 } else {
798 regs.usp = m68k_areg(regs, 7);
799 m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
800 }
801 } else if (olds && oldm != regs.m) {
802 if (oldm) {
803 regs.msp = m68k_areg(regs, 7);
804 m68k_areg(regs, 7) = regs.isp;
805 } else {
806 regs.isp = m68k_areg(regs, 7);
807 m68k_areg(regs, 7) = regs.msp;
808 }
809 }
810 } else {
811 /* [NP] If cpu < 68020, m and t0 are ignored and should be set to 0 */
812 regs.t0 = 0;
813 regs.m = 0;
814
815 if (olds != regs.s) {
816 if (olds) {
817 regs.isp = m68k_areg(regs, 7);
818 m68k_areg(regs, 7) = regs.usp;
819 } else {
820 regs.usp = m68k_areg(regs, 7);
821 m68k_areg(regs, 7) = regs.isp;
822 }
823 }
824 }
825
826 /* Pending interrupts can occur again after a write to the SR: */
827 set_special (SPCFLAG_DOINT);
828 if (regs.t1 || regs.t0)
829 set_special (SPCFLAG_TRACE);
830 else
831 /* Keep SPCFLAG_DOTRACE, we still want a trace exception for
832 SR-modifying instructions (including STOP). */
833 unset_special (SPCFLAG_TRACE);
834 }
835
836
exception_trace(int nr)837 static void exception_trace (int nr)
838 {
839 unset_special (SPCFLAG_TRACE | SPCFLAG_DOTRACE);
840 if (regs.t1 && !regs.t0) {
841 /* trace stays pending if exception is div by zero, chk,
842 * trapv or trap #x
843 */
844 if (nr == 5 || nr == 6 || nr == 7 || (nr >= 32 && nr <= 47))
845 set_special (SPCFLAG_DOTRACE);
846 }
847 regs.t1 = regs.t0 = regs.m = 0;
848 }
849
850
851 /*
852 * Compute the number of jitter cycles to add when a video interrupt occurs
853 * (this is specific to the Atari ST)
854 */
InterruptAddJitter(int Level,int Pending)855 static void InterruptAddJitter (int Level , int Pending)
856 {
857 int cycles = 0;
858
859 if ( Level == 2 ) /* HBL */
860 {
861 if ( Pending )
862 cycles = HblJitterArrayPending[ HblJitterIndex ];
863 else
864 cycles = HblJitterArray[ HblJitterIndex ];
865 }
866
867 else if ( Level == 4 ) /* VBL */
868 {
869 if ( Pending )
870 cycles = VblJitterArrayPending[ VblJitterIndex ];
871 else
872 cycles = VblJitterArray[ VblJitterIndex ];
873 }
874
875 //fprintf ( stderr , "jitter %d\n" , cycles );
876 //cycles=0;
877 if ( cycles > 0 ) /* no need to call M68000_AddCycles if cycles == 0 */
878 M68000_AddCycles ( cycles );
879 }
880
881
882 /* Handle exceptions. We need a special case to handle MFP exceptions */
883 /* on Atari ST, because it's possible to change the MFP's vector base */
884 /* and get a conflict with 'normal' cpu exceptions. */
Exception(int nr,uaecptr oldpc,int ExceptionSource)885 void Exception(int nr, uaecptr oldpc, int ExceptionSource)
886 {
887 uae_u32 currpc = m68k_getpc () , newpc;
888
889 /*if( nr>=2 && nr<10 ) fprintf(stderr,"Exception (-> %i bombs)!\n",nr);*/
890
891 /* Pending bits / vector number can change before the end of the IACK sequence. */
892 /* We need to handle MFP and HBL/VBL cases for this. */
893 if ( ExceptionSource == M68000_EXC_SRC_INT_MFP )
894 {
895 M68000_AddCycles ( CPU_IACK_CYCLES_START+CPU_IACK_CYCLES_MFP );
896 CPU_IACK = true;
897 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
898 CALL_VAR(PendingInterruptFunction);
899 nr = MFP_ProcessIACK ( nr );
900 CPU_IACK = false;
901 }
902 else if ( ( ExceptionSource == M68000_EXC_SRC_AUTOVEC ) && ( ( nr == 26 ) || ( nr == 28 ) ) )
903 {
904 M68000_AddCycles ( CPU_IACK_CYCLES_START+CPU_IACK_CYCLES_VIDEO );
905 CPU_IACK = true;
906 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
907 CALL_VAR(PendingInterruptFunction);
908 if ( MFP_UpdateNeeded == true )
909 MFP_UpdateIRQ ( 0 ); /* update MFP's state if some internal timers related to MFP expired */
910 pendingInterrupts &= ~( 1 << ( nr - 24 ) ); /* clear HBL or VBL pending bit */
911 CPU_IACK = false;
912 }
913
914
915 if (ExceptionSource == M68000_EXC_SRC_CPU)
916 {
917 if (nr == 0x22)
918 {
919 /* Intercept VDI & AES exceptions (Trap #2) */
920 if(bVdiAesIntercept && VDI_AES_Entry())
921 {
922 /* Set 'PC' to address of 'VDI_OPCODE' illegal instruction.
923 * This will call OpCode_VDI() after completion of Trap call!
924 * This is used to modify specific VDI return vectors contents.
925 */
926 VDI_OldPC = currpc;
927 currpc = CART_VDI_OPCODE_ADDR;
928 }
929 }
930 else if (nr == 0x2d)
931 {
932 /* Intercept BIOS (Trap #13) calls */
933 if (Bios()) return;
934 }
935 else if (nr == 0x2e)
936 {
937 /* Intercept XBIOS (Trap #14) calls */
938 if (XBios()) return;
939 }
940 }
941
942 MakeSR();
943
944 /* Change to supervisor mode if necessary */
945 if (!regs.s) {
946 regs.usp = m68k_areg(regs, 7);
947 if (currprefs.cpu_level >= 2)
948 m68k_areg(regs, 7) = regs.m ? regs.msp : regs.isp;
949 else
950 m68k_areg(regs, 7) = regs.isp;
951 regs.s = 1;
952 }
953
954 /* Build additional exception stack frame for 68010 and higher */
955 /* (special case for MFP) */
956 if (currprefs.cpu_level > 0) {
957 if (ExceptionSource == M68000_EXC_SRC_INT_MFP
958 || ExceptionSource == M68000_EXC_SRC_INT_DSP) {
959 m68k_areg(regs, 7) -= 2;
960 put_word (m68k_areg(regs, 7), nr * 4); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */
961 }
962 else if (nr == 2 || nr == 3) {
963 int i;
964 /* @@@ this is probably wrong (?) */
965 for (i = 0 ; i < 12 ; i++) {
966 m68k_areg(regs, 7) -= 2;
967 put_word (m68k_areg(regs, 7), 0);
968 }
969 m68k_areg(regs, 7) -= 2;
970 put_word (m68k_areg(regs, 7), 0xa000 + nr * 4);
971 } else if (nr ==5 || nr == 6 || nr == 7 || nr == 9) {
972 m68k_areg(regs, 7) -= 4;
973 put_long (m68k_areg(regs, 7), oldpc);
974 m68k_areg(regs, 7) -= 2;
975 put_word (m68k_areg(regs, 7), 0x2000 + nr * 4);
976 } else if (regs.m && nr >= 24 && nr < 32) {
977 m68k_areg(regs, 7) -= 2;
978 put_word (m68k_areg(regs, 7), nr * 4);
979 m68k_areg(regs, 7) -= 4;
980 put_long (m68k_areg(regs, 7), currpc);
981 m68k_areg(regs, 7) -= 2;
982 put_word (m68k_areg(regs, 7), regs.sr);
983 regs.sr |= (1 << 13);
984 regs.msp = m68k_areg(regs, 7);
985 m68k_areg(regs, 7) = regs.isp;
986 m68k_areg(regs, 7) -= 2;
987 put_word (m68k_areg(regs, 7), 0x1000 + nr * 4);
988 } else {
989 m68k_areg(regs, 7) -= 2;
990 put_word (m68k_areg(regs, 7), nr * 4);
991 }
992 }
993
994 /* Push PC on stack: */
995 m68k_areg(regs, 7) -= 4;
996 put_long (m68k_areg(regs, 7), currpc);
997 /* Push SR on stack: */
998 m68k_areg(regs, 7) -= 2;
999 put_word (m68k_areg(regs, 7), regs.sr);
1000
1001 LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x\n",
1002 nr, currpc, regs.instruction_pc, get_long (regs.vbr + 4*nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3);
1003
1004 /* 68000 bus/address errors: */
1005 if (currprefs.cpu_level==0 && (nr==2 || nr==3) && ExceptionSource == M68000_EXC_SRC_CPU) {
1006 uae_u16 specialstatus = last_instructionaccess_for_exception_3 ? 2 : 1;
1007 uae_u16 BusError_opcode;
1008
1009 /* Special status word emulation isn't perfect yet... :-( */
1010 if (regs.sr & 0x2000)
1011 specialstatus |= 0x4;
1012 m68k_areg(regs, 7) -= 8;
1013 if (nr == 3) { /* Address error */
1014 specialstatus |= ( last_op_for_exception_3 & (~0x1f) ); /* [NP] unused bits of specialstatus are those of the last opcode ! */
1015 if (last_writeaccess_for_exception_3==0)
1016 specialstatus |= 0x10; /* bit 4 : 0=write 1=read */
1017 put_word (m68k_areg(regs, 7), specialstatus);
1018 put_long (m68k_areg(regs, 7)+2, last_fault_for_exception_3);
1019 put_word (m68k_areg(regs, 7)+6, last_op_for_exception_3);
1020 put_long (m68k_areg(regs, 7)+10, last_addr_for_exception_3);
1021
1022 /* [NP] PC stored in the stack frame is not necessarily pointing to the next instruction ! */
1023 /* FIXME : we should have a proper model for this, in the meantime we handle specific cases */
1024 if ( last_op_for_exception_3 == 0x2285 ) /* move.l d5,(a1) (War Heli) */
1025 put_long (m68k_areg(regs, 7)+10, currpc+4); /* correct PC is 2 bytes more than usual value */
1026
1027 fprintf(stderr,"Address Error at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",last_fault_for_exception_3, currpc, last_addr_for_exception_3, last_op_for_exception_3);
1028 if (ExceptionDebugMask & EXCEPT_ADDRESS) {
1029 DebugUI(REASON_CPU_EXCEPTION);
1030 }
1031 }
1032 else { /* Bus error */
1033 /* Get the opcode that caused the bus error, to adapt the stack frame in some cases */
1034 BusError_opcode = regs.opcode;
1035
1036 specialstatus |= ( BusError_opcode & (~0x1f) ); /* [NP] unused bits of special status are those of the last opcode ! */
1037 if (bBusErrorReadWrite)
1038 specialstatus |= 0x10; /* bit 4 : 0=write 1=read */
1039 put_word (m68k_areg(regs, 7), specialstatus);
1040 put_long (m68k_areg(regs, 7)+2, BusErrorAddress);
1041 put_word (m68k_areg(regs, 7)+6, BusError_opcode); /* Opcode */
1042
1043 /* [NP] PC stored in the stack frame is not necessarily pointing to the next instruction ! */
1044 /* FIXME : we should have a proper model for this, in the meantime we handle specific cases */
1045 if ( BusError_opcode == 0x21f8 ) /* move.l $0.w,$24.w (Transbeauce 2 loader) */
1046 put_long (m68k_areg(regs, 7)+10, currpc-2); /* correct PC is 2 bytes less than usual value */
1047
1048 else if ( ( regs.instruction_pc == 0xccc ) && ( BusError_opcode == 0x48d6 ) ) /* 48d6 3f00 movem.l a0-a5,(a6) (Blood Money) */
1049 put_long (m68k_areg(regs, 7)+10, currpc+2); /* correct PC is 2 bytes more than usual value */
1050
1051 else if ( ( regs.instruction_pc == 0x1fece ) && ( BusError_opcode == 0x33d4 ) ) /* 1fece : 33d4 0001 fdca move.w (a4),$1fdca (Batman The Movie) */
1052 put_long (m68k_areg(regs, 7)+10, currpc-4); /* correct PC is 4 bytes less than usual value */
1053
1054 /* [NP] In case of a move with a bus error on the read part, uae cpu is writing to the dest part */
1055 /* then process the bus error ; on a real CPU, the bus error occurs after the read and before the */
1056 /* write, so the dest part doesn't change. For now, we restore the dest part on some specific cases */
1057 /* FIXME : the bus error should be processed just after the read, not at the end of the instruction */
1058 else if ( ( regs.instruction_pc == 0x62a ) && ( BusError_opcode == 0x3079 ) ) /* 3079 4ef9 0000 move.l $4ef90000,a0 (Dragon Flight) */
1059 m68k_areg(regs, 0) = 8; /* A0 should not be changed to "0" but keep its value "8" */
1060
1061 else if ( get_long(regs.instruction_pc) == 0x13f88e21 ) /* 13f8 8e21 move.b $ffff8e21.w,$xxxxx (Tymewarp) */
1062 put_byte ( get_long(regs.instruction_pc+4) , 0x00 ); /* dest content should not be changed to "ff" but keep its value "00" */
1063
1064 if (M68000_IsVerboseBusError(currpc, BusErrorAddress)) {
1065 Log_Printf(LOG_WARN, "Bus Error at address $%x, PC=$%x addr_e3=%x op_e3=%x\n",
1066 BusErrorAddress, currpc,
1067 get_long(m68k_areg(regs, 7) + 10), BusError_opcode);
1068 }
1069
1070 /* Check for double bus errors: */
1071 if (regs.spcflags & SPCFLAG_BUSERROR) {
1072 fprintf(stderr, "Detected double bus error at address $%x, PC=$%lx => CPU halted!\n", BusErrorAddress, (long)currpc);
1073 cpu_halt();
1074 return;
1075 }
1076 if ((ExceptionDebugMask & EXCEPT_BUS) && BusErrorAddress!=0xff8a00) {
1077 fprintf(stderr,"Bus Error at address $%x, PC=$%lx\n", BusErrorAddress, (long)currpc);
1078 DebugUI(REASON_CPU_EXCEPTION);
1079 }
1080 }
1081 }
1082
1083 /* Set PC and flags */
1084 if ((ExceptionDebugMask & EXCEPT_NOHANDLER) && (regs.vbr + 4*nr) == 0) {
1085 fprintf(stderr,"Uninitialized exception handler #%i!\n", nr);
1086 DebugUI(REASON_CPU_EXCEPTION);
1087 }
1088 newpc = get_long (regs.vbr + 4*nr);
1089 if ( newpc & 1) /* check new pc is even */
1090 {
1091 if ( nr==2 || nr==3 ) /* address error during bus/address error -> stop emulation */
1092 {
1093 fprintf(stderr,"Address Error during exception 2/3, new PC=$%x => CPU halted\n",newpc);
1094 cpu_halt();
1095 }
1096 else
1097 {
1098 fprintf(stderr,"Address Error during exception, new PC=$%x\n",newpc);
1099 Exception ( 3 , m68k_getpc() , M68000_EXC_SRC_CPU );
1100 }
1101 return;
1102 }
1103 /* handle debugger invocation for rest of exceptions */
1104 if (ExceptionDebugMask && nr > 3 && nr < 9)
1105 DebugUI_Exceptions(nr, currpc);
1106
1107 m68k_setpc (get_long (regs.vbr + 4*nr));
1108 fill_prefetch_0 ();
1109 /* Handle trace flags depending on current state */
1110 exception_trace (nr);
1111
1112 /* Handle exception cycles (special case for MFP) */
1113 if (ExceptionSource == M68000_EXC_SRC_INT_MFP)
1114 {
1115 M68000_AddCycles(44+12-CPU_IACK_CYCLES_START-CPU_IACK_CYCLES_MFP); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */
1116 }
1117 else if (nr >= 24 && nr <= 31)
1118 {
1119 if ( nr == 26 ) /* HBL */
1120 M68000_AddCycles(44+12-CPU_IACK_CYCLES_START-CPU_IACK_CYCLES_VIDEO); /* Video Interrupt */
1121 else if ( nr == 28 ) /* VBL */
1122 M68000_AddCycles(44+12-CPU_IACK_CYCLES_START-CPU_IACK_CYCLES_VIDEO); /* Video Interrupt */
1123 else
1124 M68000_AddCycles(44+4); /* Other Interrupts */
1125 }
1126 else if(nr >= 32 && nr <= 47)
1127 {
1128 M68000_AddCycles(34-4); /* Trap (total is 34, but cpuemu.c already adds 4) */
1129 }
1130 else switch(nr)
1131 {
1132 case 2: M68000_AddCycles(50); break; /* Bus error */
1133 case 3: M68000_AddCycles(50); break; /* Address error */
1134 case 4: M68000_AddCycles(34); break; /* Illegal instruction */
1135 case 5: M68000_AddCycles(38); break; /* Div by zero */
1136 case 6: M68000_AddCycles(40); break; /* CHK */
1137 case 7: M68000_AddCycles(34); break; /* TRAPV */
1138 case 8: M68000_AddCycles(34); break; /* Privilege violation */
1139 case 9: M68000_AddCycles(34); break; /* Trace */
1140 case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */
1141 case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */
1142 default:
1143 /* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */
1144 if(nr < 64)
1145 M68000_AddCycles(4); /* Coprocessor and unassigned exceptions (???) */
1146 else
1147 M68000_AddCycles(44+12); /* Must be a MFP or DSP interrupt */
1148 break;
1149 }
1150
1151 }
1152
1153
Interrupt(int nr,int Pending)1154 static void Interrupt(int nr , int Pending)
1155 {
1156 assert(nr < 8 && nr >= 0);
1157 /*lastint_regs = regs;*/
1158 /*lastint_no = nr;*/
1159
1160 /* On Hatari, only video ints are using SPCFLAG_INT (see m68000.c) */
1161 Exception(nr+24, 0, M68000_EXC_SRC_AUTOVEC);
1162
1163 regs.intmask = nr;
1164 set_special (SPCFLAG_INT);
1165
1166 /* Handle Atari ST's specific jitter for hbl/vbl */
1167 InterruptAddJitter ( nr , Pending );
1168 }
1169
1170
1171 static uae_u32 itt0, itt1, dtt0, dtt1, tc, mmusr, urp, srp;
1172
1173
movec_illg(int regno)1174 static int movec_illg (int regno)
1175 {
1176 int regno2 = regno & 0x7ff;
1177 if (currprefs.cpu_level == 1) { /* 68010 */
1178 if (regno2 < 2)
1179 return 0;
1180 return 1;
1181 }
1182 if (currprefs.cpu_level == 2 || currprefs.cpu_level == 3) { /* 68020 */
1183 if (regno == 3) return 1; /* 68040 only */
1184 /* 4 is >=68040, but 0x804 is in 68020 */
1185 if (regno2 < 4 || regno == 0x804)
1186 return 0;
1187 return 1;
1188 }
1189 if (currprefs.cpu_level >= 4) { /* 68040 */
1190 if (regno == 0x802) return 1; /* 68020 only */
1191 if (regno2 < 8) return 0;
1192 if (currprefs.cpu_level == 6 && regno2 == 8) /* 68060 only */
1193 return 0;
1194 return 1;
1195 }
1196 return 1;
1197 }
1198
m68k_move2c(int regno,uae_u32 * regp)1199 int m68k_move2c (int regno, uae_u32 *regp)
1200 {
1201 if (movec_illg (regno)) {
1202 op_illg (0x4E7B);
1203 return 0;
1204 } else {
1205 switch (regno) {
1206 case 0: regs.sfc = *regp & 7; break;
1207 case 1: regs.dfc = *regp & 7; break;
1208 case 2:
1209 {
1210 uae_u32 cacr_mask = 0;
1211 if (currprefs.cpu_level == 2) // 68020
1212 cacr_mask = 0x0000000f;
1213 else if (currprefs.cpu_level == 3) // Fake 68030
1214 cacr_mask = 0x00003f1f;
1215 else if (currprefs.cpu_level == 4) // 68040
1216 cacr_mask = 0x80008000;
1217 regs.cacr = *regp & cacr_mask;
1218 }
1219 case 3: tc = *regp & 0xc000; break;
1220 /* Mask out fields that should be zero. */
1221 case 4: itt0 = *regp & 0xffffe364; break;
1222 case 5: itt1 = *regp & 0xffffe364; break;
1223 case 6: dtt0 = *regp & 0xffffe364; break;
1224 case 7: dtt1 = *regp & 0xffffe364; break;
1225
1226 case 0x800: regs.usp = *regp; break;
1227 case 0x801: regs.vbr = *regp; break;
1228 case 0x802: regs.caar = *regp; break;
1229 case 0x803: regs.msp = *regp; if (regs.m == 1) m68k_areg(regs, 7) = regs.msp; break;
1230 case 0x804: regs.isp = *regp; if (regs.m == 0) m68k_areg(regs, 7) = regs.isp; break;
1231 case 0x805: mmusr = *regp; break;
1232 case 0x806: urp = *regp; break;
1233 case 0x807: srp = *regp; break;
1234 default:
1235 op_illg (0x4E7B);
1236 return 0;
1237 }
1238 }
1239 return 1;
1240 }
1241
m68k_movec2(int regno,uae_u32 * regp)1242 int m68k_movec2 (int regno, uae_u32 *regp)
1243 {
1244 if (movec_illg (regno)) {
1245 op_illg (0x4E7A);
1246 return 0;
1247 } else {
1248 switch (regno) {
1249 case 0: *regp = regs.sfc; break;
1250 case 1: *regp = regs.dfc; break;
1251 case 2: *regp = regs.cacr; break;
1252 case 3: *regp = tc; break;
1253 case 4: *regp = itt0; break;
1254 case 5: *regp = itt1; break;
1255 case 6: *regp = dtt0; break;
1256 case 7: *regp = dtt1; break;
1257 case 0x800: *regp = regs.usp; break;
1258 case 0x801: *regp = regs.vbr; break;
1259 case 0x802: *regp = regs.caar; break;
1260 case 0x803: *regp = regs.m == 1 ? m68k_areg(regs, 7) : regs.msp; break;
1261 case 0x804: *regp = regs.m == 0 ? m68k_areg(regs, 7) : regs.isp; break;
1262 case 0x805: *regp = mmusr; break;
1263 case 0x806: *regp = urp; break;
1264 case 0x807: *regp = srp; break;
1265 default:
1266 op_illg (0x4E7A);
1267 return 0;
1268 }
1269 }
1270 return 1;
1271 }
1272
1273 #if !defined(uae_s64)
1274 STATIC_INLINE int
div_unsigned(uae_u32 src_hi,uae_u32 src_lo,uae_u32 ndiv,uae_u32 * quot,uae_u32 * rem)1275 div_unsigned(uae_u32 src_hi, uae_u32 src_lo, uae_u32 ndiv, uae_u32 *quot, uae_u32 *rem)
1276 {
1277 uae_u32 q = 0, cbit = 0;
1278 int i;
1279
1280 if (ndiv <= src_hi) {
1281 return 1;
1282 }
1283 for (i = 0 ; i < 32 ; i++) {
1284 cbit = src_hi & 0x80000000ul;
1285 src_hi <<= 1;
1286 if (src_lo & 0x80000000ul) src_hi++;
1287 src_lo <<= 1;
1288 q = q << 1;
1289 if (cbit || ndiv <= src_hi) {
1290 q |= 1;
1291 src_hi -= ndiv;
1292 }
1293 }
1294 *quot = q;
1295 *rem = src_hi;
1296 return 0;
1297 }
1298 #endif
1299
m68k_divl(uae_u32 opcode,uae_u32 src,uae_u16 extra,uaecptr oldpc)1300 void m68k_divl (uae_u32 opcode, uae_u32 src, uae_u16 extra, uaecptr oldpc)
1301 {
1302 #if defined(uae_s64)
1303 if (src == 0) {
1304 Exception (5, oldpc,M68000_EXC_SRC_CPU);
1305 return;
1306 }
1307 if (extra & 0x800) {
1308 /* signed variant */
1309 uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
1310 uae_s64 quot, rem;
1311
1312 if (extra & 0x400) {
1313 a &= 0xffffffffu;
1314 a |= (uae_s64)m68k_dreg(regs, extra & 7) << 32;
1315 }
1316 rem = a % (uae_s64)(uae_s32)src;
1317 quot = a / (uae_s64)(uae_s32)src;
1318 if ((quot & UVAL64(0xffffffff80000000)) != 0
1319 && (quot & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
1320 {
1321 SET_VFLG (1);
1322 SET_NFLG (1);
1323 SET_CFLG (0);
1324 } else {
1325 if (((uae_s32)rem < 0) != ((uae_s64)a < 0)) rem = -rem;
1326 SET_VFLG (0);
1327 SET_CFLG (0);
1328 SET_ZFLG (((uae_s32)quot) == 0);
1329 SET_NFLG (((uae_s32)quot) < 0);
1330 m68k_dreg(regs, extra & 7) = rem;
1331 m68k_dreg(regs, (extra >> 12) & 7) = quot;
1332 }
1333 } else {
1334 /* unsigned */
1335 uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
1336 uae_u64 quot, rem;
1337
1338 if (extra & 0x400) {
1339 a &= 0xffffffffu;
1340 a |= (uae_u64)m68k_dreg(regs, extra & 7) << 32;
1341 }
1342 rem = a % (uae_u64)src;
1343 quot = a / (uae_u64)src;
1344 if (quot > 0xffffffffu) {
1345 SET_VFLG (1);
1346 SET_NFLG (1);
1347 SET_CFLG (0);
1348 } else {
1349 SET_VFLG (0);
1350 SET_CFLG (0);
1351 SET_ZFLG (((uae_s32)quot) == 0);
1352 SET_NFLG (((uae_s32)quot) < 0);
1353 m68k_dreg(regs, extra & 7) = rem;
1354 m68k_dreg(regs, (extra >> 12) & 7) = quot;
1355 }
1356 }
1357 #else
1358 if (src == 0) {
1359 Exception (5, oldpc,M68000_EXC_SRC_CPU);
1360 return;
1361 }
1362 if (extra & 0x800) {
1363 /* signed variant */
1364 uae_s32 lo = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
1365 uae_s32 hi = lo < 0 ? -1 : 0;
1366 uae_s32 save_high;
1367 uae_u32 quot, rem;
1368 uae_u32 sign;
1369
1370 if (extra & 0x400) {
1371 hi = (uae_s32)m68k_dreg(regs, extra & 7);
1372 }
1373 save_high = hi;
1374 sign = (hi ^ src);
1375 if (hi < 0) {
1376 hi = ~hi;
1377 lo = -lo;
1378 if (lo == 0) hi++;
1379 }
1380 if ((uae_s32)src < 0) src = -src;
1381 if (div_unsigned(hi, lo, src, ", &rem) ||
1382 (sign & 0x80000000) ? quot > 0x80000000 : quot > 0x7fffffff) {
1383 SET_VFLG (1);
1384 SET_NFLG (1);
1385 SET_CFLG (0);
1386 } else {
1387 if (sign & 0x80000000) quot = -quot;
1388 if (((uae_s32)rem < 0) != (save_high < 0)) rem = -rem;
1389 SET_VFLG (0);
1390 SET_CFLG (0);
1391 SET_ZFLG (((uae_s32)quot) == 0);
1392 SET_NFLG (((uae_s32)quot) < 0);
1393 m68k_dreg(regs, extra & 7) = rem;
1394 m68k_dreg(regs, (extra >> 12) & 7) = quot;
1395 }
1396 } else {
1397 /* unsigned */
1398 uae_u32 lo = (uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
1399 uae_u32 hi = 0;
1400 uae_u32 quot, rem;
1401
1402 if (extra & 0x400) {
1403 hi = (uae_u32)m68k_dreg(regs, extra & 7);
1404 }
1405 if (div_unsigned(hi, lo, src, ", &rem)) {
1406 SET_VFLG (1);
1407 SET_NFLG (1);
1408 SET_CFLG (0);
1409 } else {
1410 SET_VFLG (0);
1411 SET_CFLG (0);
1412 SET_ZFLG (((uae_s32)quot) == 0);
1413 SET_NFLG (((uae_s32)quot) < 0);
1414 m68k_dreg(regs, extra & 7) = rem;
1415 m68k_dreg(regs, (extra >> 12) & 7) = quot;
1416 }
1417 }
1418 #endif
1419 }
1420
1421 #if !defined(uae_s64)
1422 STATIC_INLINE void
mul_unsigned(uae_u32 src1,uae_u32 src2,uae_u32 * dst_hi,uae_u32 * dst_lo)1423 mul_unsigned(uae_u32 src1, uae_u32 src2, uae_u32 *dst_hi, uae_u32 *dst_lo)
1424 {
1425 uae_u32 r0 = (src1 & 0xffff) * (src2 & 0xffff);
1426 uae_u32 r1 = ((src1 >> 16) & 0xffff) * (src2 & 0xffff);
1427 uae_u32 r2 = (src1 & 0xffff) * ((src2 >> 16) & 0xffff);
1428 uae_u32 r3 = ((src1 >> 16) & 0xffff) * ((src2 >> 16) & 0xffff);
1429 uae_u32 lo;
1430
1431 lo = r0 + ((r1 << 16) & 0xffff0000ul);
1432 if (lo < r0) r3++;
1433 r0 = lo;
1434 lo = r0 + ((r2 << 16) & 0xffff0000ul);
1435 if (lo < r0) r3++;
1436 r3 += ((r1 >> 16) & 0xffff) + ((r2 >> 16) & 0xffff);
1437 *dst_lo = lo;
1438 *dst_hi = r3;
1439 }
1440 #endif
1441
m68k_mull(uae_u32 opcode,uae_u32 src,uae_u16 extra)1442 void m68k_mull (uae_u32 opcode, uae_u32 src, uae_u16 extra)
1443 {
1444 #if defined(uae_s64)
1445 if (extra & 0x800) {
1446 /* signed variant */
1447 uae_s64 a = (uae_s64)(uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
1448
1449 a *= (uae_s64)(uae_s32)src;
1450 SET_VFLG (0);
1451 SET_CFLG (0);
1452 SET_ZFLG (a == 0);
1453 SET_NFLG (a < 0);
1454 if (extra & 0x400)
1455 m68k_dreg(regs, extra & 7) = a >> 32;
1456 else if ((a & UVAL64(0xffffffff80000000)) != 0
1457 && (a & UVAL64(0xffffffff80000000)) != UVAL64(0xffffffff80000000))
1458 {
1459 SET_VFLG (1);
1460 }
1461 m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
1462 } else {
1463 /* unsigned */
1464 uae_u64 a = (uae_u64)(uae_u32)m68k_dreg(regs, (extra >> 12) & 7);
1465
1466 a *= (uae_u64)src;
1467 SET_VFLG (0);
1468 SET_CFLG (0);
1469 SET_ZFLG (a == 0);
1470 SET_NFLG (((uae_s64)a) < 0);
1471 if (extra & 0x400)
1472 m68k_dreg(regs, extra & 7) = a >> 32;
1473 else if ((a & UVAL64(0xffffffff00000000)) != 0) {
1474 SET_VFLG (1);
1475 }
1476 m68k_dreg(regs, (extra >> 12) & 7) = (uae_u32)a;
1477 }
1478 #else
1479 if (extra & 0x800) {
1480 /* signed variant */
1481 uae_s32 src1,src2;
1482 uae_u32 dst_lo,dst_hi;
1483 uae_u32 sign;
1484
1485 src1 = (uae_s32)src;
1486 src2 = (uae_s32)m68k_dreg(regs, (extra >> 12) & 7);
1487 sign = (src1 ^ src2);
1488 if (src1 < 0) src1 = -src1;
1489 if (src2 < 0) src2 = -src2;
1490 mul_unsigned((uae_u32)src1,(uae_u32)src2,&dst_hi,&dst_lo);
1491 if (sign & 0x80000000) {
1492 dst_hi = ~dst_hi;
1493 dst_lo = -dst_lo;
1494 if (dst_lo == 0) dst_hi++;
1495 }
1496 SET_VFLG (0);
1497 SET_CFLG (0);
1498 SET_ZFLG (dst_hi == 0 && dst_lo == 0);
1499 SET_NFLG (((uae_s32)dst_hi) < 0);
1500 if (extra & 0x400)
1501 m68k_dreg(regs, extra & 7) = dst_hi;
1502 else if ((dst_hi != 0 || (dst_lo & 0x80000000) != 0)
1503 && ((dst_hi & 0xffffffff) != 0xffffffff
1504 || (dst_lo & 0x80000000) != 0x80000000))
1505 {
1506 SET_VFLG (1);
1507 }
1508 m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
1509 } else {
1510 /* unsigned */
1511 uae_u32 dst_lo,dst_hi;
1512
1513 mul_unsigned(src,(uae_u32)m68k_dreg(regs, (extra >> 12) & 7),&dst_hi,&dst_lo);
1514
1515 SET_VFLG (0);
1516 SET_CFLG (0);
1517 SET_ZFLG (dst_hi == 0 && dst_lo == 0);
1518 SET_NFLG (((uae_s32)dst_hi) < 0);
1519 if (extra & 0x400)
1520 m68k_dreg(regs, extra & 7) = dst_hi;
1521 else if (dst_hi != 0) {
1522 SET_VFLG (1);
1523 }
1524 m68k_dreg(regs, (extra >> 12) & 7) = dst_lo;
1525 }
1526 #endif
1527 }
1528
1529
m68k_reset(void)1530 void m68k_reset (void)
1531 {
1532 regs.s = 1;
1533 regs.m = 0;
1534 regs.stopped = 0;
1535 regs.t1 = 0;
1536 regs.t0 = 0;
1537 SET_ZFLG (0);
1538 SET_XFLG (0);
1539 SET_CFLG (0);
1540 SET_VFLG (0);
1541 SET_NFLG (0);
1542 regs.spcflags &= ( SPCFLAG_MODE_CHANGE | SPCFLAG_DEBUGGER ); /* Clear specialflags except mode-change and debugger */
1543 regs.intmask = 7;
1544 regs.vbr = regs.sfc = regs.dfc = 0;
1545 regs.fpcr = regs.fpsr = regs.fpiar = 0;
1546
1547 m68k_areg(regs, 7) = get_long(0);
1548 m68k_setpc(get_long(4));
1549 refill_prefetch (m68k_getpc(), 0);
1550 }
1551
1552
op_illg(uae_u32 opcode)1553 unsigned long REGPARAM2 op_illg (uae_u32 opcode)
1554 {
1555 #if 0
1556 uaecptr pc = m68k_getpc ();
1557 #endif
1558 if ((opcode & 0xF000) == 0xF000) {
1559 Exception(0xB,0,M68000_EXC_SRC_CPU);
1560 return 4;
1561 }
1562 if ((opcode & 0xF000) == 0xA000) {
1563 Exception(0xA,0,M68000_EXC_SRC_CPU);
1564 return 4;
1565 }
1566 #if 0
1567 write_log ("Illegal instruction: %04x at %08lx\n", opcode, (long)pc);
1568 #endif
1569 Exception (4,0,M68000_EXC_SRC_CPU);
1570 return 4;
1571 }
1572
1573
mmu_op(uae_u32 opcode,uae_u16 extra)1574 void mmu_op(uae_u32 opcode, uae_u16 extra)
1575 {
1576 if ((opcode & 0xFE0) == 0x0500) {
1577 /* PFLUSH */
1578 mmusr = 0;
1579 write_log ("PFLUSH\n");
1580 } else if ((opcode & 0x0FD8) == 0x548) {
1581 /* PTEST */
1582 write_log ("PTEST\n");
1583 } else
1584 op_illg (opcode);
1585 }
1586
1587
1588 static uaecptr last_trace_ad = 0;
1589
do_trace(void)1590 static void do_trace (void)
1591 {
1592 if (regs.t0 && currprefs.cpu_level >= 2) {
1593 uae_u16 opcode;
1594 /* should also include TRAP, CHK, SR modification FPcc */
1595 /* probably never used so why bother */
1596 /* We can afford this to be inefficient... */
1597 m68k_setpc (m68k_getpc ());
1598 fill_prefetch_0 ();
1599 opcode = get_word (regs.pc);
1600 if (opcode == 0x4e73 /* RTE */
1601 || opcode == 0x4e74 /* RTD */
1602 || opcode == 0x4e75 /* RTS */
1603 || opcode == 0x4e77 /* RTR */
1604 || opcode == 0x4e76 /* TRAPV */
1605 || (opcode & 0xffc0) == 0x4e80 /* JSR */
1606 || (opcode & 0xffc0) == 0x4ec0 /* JMP */
1607 || (opcode & 0xff00) == 0x6100 /* BSR */
1608 || ((opcode & 0xf000) == 0x6000 /* Bcc */
1609 && cctrue((opcode >> 8) & 0xf))
1610 || ((opcode & 0xf0f0) == 0x5050 /* DBcc */
1611 && !cctrue((opcode >> 8) & 0xf)
1612 && (uae_s16)m68k_dreg(regs, opcode & 7) != 0))
1613 {
1614 last_trace_ad = m68k_getpc ();
1615 unset_special (SPCFLAG_TRACE);
1616 set_special (SPCFLAG_DOTRACE);
1617 }
1618 } else if (regs.t1) {
1619 last_trace_ad = m68k_getpc ();
1620 unset_special (SPCFLAG_TRACE);
1621 set_special (SPCFLAG_DOTRACE);
1622 }
1623 }
1624
1625
1626 /*
1627 * Handle special flags
1628 */
1629
do_specialties_interrupt(int Pending)1630 static bool do_specialties_interrupt (int Pending)
1631 {
1632 #if ENABLE_DSP_EMU
1633 /* Check for DSP int first (if enabled) (level 6) */
1634 if (regs.spcflags & SPCFLAG_DSP) {
1635 if (DSP_ProcessIRQ() == true)
1636 return true;
1637 }
1638 #endif
1639
1640 /* Check for MFP ints (level 6) */
1641 if (regs.spcflags & SPCFLAG_MFP) {
1642 if (MFP_ProcessIRQ() == true)
1643 return true; /* MFP exception was generated, no higher interrupt can happen */
1644 }
1645
1646 /* No MFP int, check for VBL/HBL ints (levels 4/2) */
1647 if (regs.spcflags & (SPCFLAG_INT | SPCFLAG_DOINT)) {
1648 int intr = intlev ();
1649 /* SPCFLAG_DOINT will be enabled again in MakeFromSR to handle pending interrupts! */
1650 // unset_special (SPCFLAG_DOINT);
1651 unset_special (SPCFLAG_INT | SPCFLAG_DOINT);
1652 if (intr != -1 && intr > regs.intmask) {
1653 Interrupt (intr , Pending); /* process the interrupt and add pending jitter if necessary */
1654 return true;
1655 }
1656 }
1657
1658 return false; /* no interrupt was found */
1659 }
1660
1661
do_specialties(void)1662 static int do_specialties (void)
1663 {
1664 if(regs.spcflags & SPCFLAG_BUSERROR) {
1665 /* We can not execute bus errors directly in the memory handler
1666 * functions since the PC should point to the address of the next
1667 * instruction, so we're executing the bus errors here: */
1668 unset_special(SPCFLAG_BUSERROR);
1669 Exception(2,0,M68000_EXC_SRC_CPU);
1670 }
1671
1672 if ( WaitStateCycles ) {
1673 /* Add some extra cycles to simulate a wait state */
1674 M68000_AddCycles(WaitStateCycles);
1675 WaitStateCycles = 0;
1676 }
1677
1678 if (regs.spcflags & SPCFLAG_DOTRACE) {
1679 Exception (9,last_trace_ad,M68000_EXC_SRC_CPU);
1680 }
1681
1682
1683 /* Handle the STOP instruction */
1684 if ( regs.spcflags & SPCFLAG_STOP ) {
1685 //fprintf ( stderr , "test stop %d\n" , nCyclesMainCounter );
1686 /* We first test if there's a pending interrupt that would */
1687 /* allow to immediately leave the STOP state */
1688 if ( do_specialties_interrupt(true) ) { /* test if there's an interrupt and add pending jitter */
1689 regs.stopped = 0;
1690 unset_special (SPCFLAG_STOP);
1691 //fprintf ( stderr , "exit stop %d\n" , nCyclesMainCounter );
1692 }
1693
1694 /* No pending int, we have to wait for the next matching int */
1695 while (regs.spcflags & SPCFLAG_STOP) {
1696
1697 /* Take care of quit event if needed */
1698 if (regs.spcflags & SPCFLAG_BRK)
1699 return 1;
1700
1701 M68000_AddCycles(4);
1702
1703 /* It is possible one or more ints happen at the same time */
1704 /* We must process them during the same cpu cycle then choose the highest priority one */
1705 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
1706 CALL_VAR(PendingInterruptFunction);
1707 if ( MFP_UpdateNeeded == true )
1708 MFP_UpdateIRQ ( 0 );
1709
1710 /* Check is there's an interrupt to process (could be a delayed MFP interrupt) */
1711 if ( do_specialties_interrupt(false) ) { /* test if there's an interrupt and add non pending jitter */
1712 regs.stopped = 0;
1713 unset_special (SPCFLAG_STOP);
1714 }
1715 }
1716 }
1717
1718
1719 if (regs.spcflags & SPCFLAG_TRACE)
1720 do_trace ();
1721
1722 // if (regs.spcflags & SPCFLAG_DOINT) {
1723 /* [NP] pending int should be processed now, not after the current instr */
1724 /* so we check for (SPCFLAG_INT | SPCFLAG_DOINT), not just for SPCFLAG_DOINT */
1725
1726 if ( do_specialties_interrupt(false) ) { /* test if there's an interrupt and add non pending jitter */
1727 regs.stopped = 0; /* [NP] useless ? */
1728 }
1729 if (regs.spcflags & SPCFLAG_INT) {
1730 unset_special (SPCFLAG_INT);
1731 set_special (SPCFLAG_DOINT);
1732 }
1733
1734 if (regs.spcflags & SPCFLAG_DEBUGGER)
1735 DebugCpu_Check();
1736
1737 if (regs.spcflags & (SPCFLAG_BRK | SPCFLAG_MODE_CHANGE)) {
1738 unset_special(SPCFLAG_MODE_CHANGE);
1739 return 1;
1740 }
1741
1742 return 0;
1743 }
1744
1745
1746 /* It's really sad to have two almost identical functions for this, but we
1747 do it all for performance... :( */
m68k_run_1(void)1748 static void m68k_run_1 (void)
1749 {
1750 #ifdef DEBUG_PREFETCH
1751 uae_u8 saved_bytes[20];
1752 uae_u8 *oldpcp;
1753 #endif
1754
1755 for (;;) {
1756 int cycles;
1757 //fprintf (stderr, "ir in %x %x\n",do_get_mem_long(®s.prefetch) , regs.prefetch_pc);
1758 regs.opcode = get_iword_prefetch (0);
1759
1760 if (regs.spcflags & SPCFLAG_BUSERROR)
1761 {
1762 unset_special(SPCFLAG_BUSERROR);
1763 Exception(2,0,M68000_EXC_SRC_CPU);
1764
1765 /* Get opcode for bus error handler and check other special bits */
1766 regs.opcode = get_iword_prefetch (0);
1767 if (regs.spcflags) {
1768 if (do_specialties ())
1769 return;
1770 }
1771 }
1772
1773 #ifdef DEBUG_PREFETCH
1774 // if (get_ilong (0) != do_get_mem_long (®s.prefetch)) {
1775 // fprintf (stderr, "Prefetch differs from memory.\n");
1776 // debugging = 1;
1777 // return;
1778 // }
1779 oldpcp = regs.pc_p;
1780 memcpy (saved_bytes, regs.pc_p, 20);
1781 #endif
1782
1783 /*m68k_dumpstate(stderr, NULL);*/
1784 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
1785 {
1786 int FrameCycles, HblCounterVideo, LineCycles;
1787
1788 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1789
1790 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1791 Disasm(stderr, m68k_getpc (), NULL, 1);
1792 }
1793
1794 /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */
1795 /* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/
1796 #if COUNT_INSTRS == 2
1797 if (table68k[regs.opcode].handler != -1)
1798 instrcount[table68k[regs.opcode].handler]++;
1799 #elif COUNT_INSTRS == 1
1800 instrcount[regs.opcode]++;
1801 #endif
1802
1803 /* In case of a Bus Error, we need the PC of the instruction that caused */
1804 /* the error to build the exception stack frame */
1805 regs.instruction_pc = m68k_getpc();
1806
1807 if (bDspEnabled)
1808 Cycles_SetCounter(CYCLES_COUNTER_CPU, 0); /* to measure the total number of cycles spent in the cpu */
1809
1810 /* Uncomment following lines to call capslib's debugger after each instruction */
1811 //if ( CAPSGetDebugRequest() )
1812 // DebugUI(REASON_CPU_BREAKPOINT);
1813
1814 cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
1815 //fprintf (stderr, "ir out %x %x\n",do_get_mem_long(®s.prefetch) , regs.prefetch_pc);
1816
1817 #ifdef DEBUG_PREFETCH
1818 if (memcmp (saved_bytes, oldpcp, 20) != 0) {
1819 fprintf (stderr, "Self-modifying code detected %x.\n" , m68k_getpc() );
1820 // set_special (SPCFLAG_BRK);
1821 // debugging = 1;
1822 }
1823 #endif
1824
1825 M68000_AddCyclesWithPairing(cycles);
1826
1827 if ( WaitStateCycles ) {
1828 /* Add some extra cycles to simulate a wait state */
1829 M68000_AddCycles(WaitStateCycles);
1830 WaitStateCycles = 0;
1831 }
1832
1833 /* We can have several interrupts at the same time before the next CPU instruction */
1834 /* We must check for pending interrupt and call do_specialties_interrupt() only */
1835 /* if the cpu is not in the STOP state. Else, the int could be acknowledged now */
1836 /* and prevent exiting the STOP state when calling do_specialties() after. */
1837 /* For performance, we first test PendingInterruptCount, then regs.spcflags */
1838 if ( PendingInterruptCount <= 0 )
1839 {
1840 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) && ( ( regs.spcflags & SPCFLAG_STOP ) == 0 ) )
1841 CALL_VAR ( PendingInterruptFunction ); /* call the interrupt's handler */
1842 if ( MFP_UpdateNeeded == true )
1843 MFP_UpdateIRQ ( 0 ); /* update MFP's state if some internal timers related to MFP expired */
1844 }
1845
1846 if (regs.spcflags) {
1847 if (do_specialties ())
1848 return;
1849 }
1850
1851 /* Run DSP 56k code if necessary */
1852 if (bDspEnabled) {
1853 DSP_Run( Cycles_GetCounter(CYCLES_COUNTER_CPU) * DSP_CPU_FREQ_RATIO);
1854 }
1855 }
1856 }
1857
1858
1859 /* Same thing, but don't use prefetch to get opcode. */
m68k_run_2(void)1860 static void m68k_run_2 (void)
1861 {
1862 for (;;) {
1863 int cycles;
1864
1865 regs.opcode = get_iword (0);
1866
1867 /*m68k_dumpstate(stderr, NULL);*/
1868 if (LOG_TRACE_LEVEL(TRACE_CPU_DISASM))
1869 {
1870 int FrameCycles, HblCounterVideo, LineCycles;
1871
1872 Video_GetPosition ( &FrameCycles , &HblCounterVideo , &LineCycles );
1873
1874 LOG_TRACE_PRINT ( "cpu video_cyc=%6d %3d@%3d : " , FrameCycles, LineCycles, HblCounterVideo );
1875 Disasm(stderr, m68k_getpc (), NULL, 1);
1876 }
1877
1878 /* assert (!regs.stopped && !(regs.spcflags & SPCFLAG_STOP)); */
1879 /* regs_backup[backup_pointer = (backup_pointer + 1) % 16] = regs;*/
1880 #if COUNT_INSTRS == 2
1881 if (table68k[regs.opcode].handler != -1)
1882 instrcount[table68k[regs.opcode].handler]++;
1883 #elif COUNT_INSTRS == 1
1884 instrcount[regs.opcode]++;
1885 #endif
1886
1887 /* In case of a Bus Error, we need the PC of the instruction that caused */
1888 /* the error to build the exception stack frame */
1889 regs.instruction_pc = m68k_getpc();
1890
1891 cycles = (*cpufunctbl[regs.opcode])(regs.opcode);
1892
1893 if (bDspEnabled)
1894 Cycles_SetCounter(CYCLES_COUNTER_CPU, 0); /* to measure the total number of cycles spent in the cpu */
1895
1896 M68000_AddCycles(cycles);
1897
1898 if ( WaitStateCycles ) {
1899 /* Add some extra cycles to simulate a wait state */
1900 M68000_AddCycles(WaitStateCycles);
1901 WaitStateCycles = 0;
1902 }
1903
1904 if ( PendingInterruptCount <= 0 )
1905 {
1906 while ( ( PendingInterruptCount <= 0 ) && ( PendingInterruptFunction ) )
1907 CALL_VAR(PendingInterruptFunction);
1908 if ( MFP_UpdateNeeded == true )
1909 MFP_UpdateIRQ ( 0 );
1910 }
1911
1912 if (regs.spcflags) {
1913 if (do_specialties ())
1914 return;
1915 }
1916
1917 /* Run DSP 56k code if necessary */
1918 if (bDspEnabled) {
1919 DSP_Run( Cycles_GetCounter(CYCLES_COUNTER_CPU) * DSP_CPU_FREQ_RATIO);
1920 }
1921 }
1922 }
1923
1924
m68k_go(int may_quit)1925 void m68k_go (int may_quit)
1926 {
1927 static int in_m68k_go = 0;
1928
1929 if (in_m68k_go || !may_quit) {
1930 write_log ("Bug! m68k_go is not reentrant.\n");
1931 abort ();
1932 }
1933
1934 in_m68k_go++;
1935 while (!(regs.spcflags & SPCFLAG_BRK)) {
1936 if(currprefs.cpu_compatible)
1937 m68k_run_1();
1938 else
1939 m68k_run_2();
1940 }
1941 unset_special(SPCFLAG_BRK);
1942 in_m68k_go--;
1943 }
1944
1945
1946 /*
1947 static void m68k_verify (uaecptr addr, uaecptr *nextpc)
1948 {
1949 uae_u32 opcode, val;
1950 struct instr *dp;
1951
1952 opcode = get_iword_1(0);
1953 last_op_for_exception_3 = opcode;
1954 m68kpc_offset = 2;
1955
1956 if (cpufunctbl[opcode] == op_illg_1) {
1957 opcode = 0x4AFC;
1958 }
1959 dp = table68k + opcode;
1960
1961 if (dp->suse) {
1962 if (!verify_ea (dp->sreg, dp->smode, dp->size, &val)) {
1963 Exception (3, 0,M68000_EXC_SRC_CPU);
1964 return;
1965 }
1966 }
1967 if (dp->duse) {
1968 if (!verify_ea (dp->dreg, dp->dmode, dp->size, &val)) {
1969 Exception (3, 0,M68000_EXC_SRC_CPU);
1970 return;
1971 }
1972 }
1973 }
1974 */
1975
1976
m68k_disasm(FILE * f,uaecptr addr,uaecptr * nextpc,int cnt)1977 void m68k_disasm (FILE *f, uaecptr addr, uaecptr *nextpc, int cnt)
1978 {
1979 static const char * const ccnames[] =
1980 { "T ","F ","HI","LS","CC","CS","NE","EQ",
1981 "VC","VS","PL","MI","GE","LT","GT","LE" };
1982
1983 uaecptr newpc = 0;
1984 m68kpc_offset = addr - m68k_getpc ();
1985 while (cnt-- > 0) {
1986 char instrname[20],*ccpt;
1987 int opwords;
1988 uae_u32 opcode;
1989 const struct mnemolookup *lookup;
1990 struct instr *dp;
1991 fprintf (f, "%08lx: ", m68k_getpc () + m68kpc_offset);
1992 for (opwords = 0; opwords < 5; opwords++){
1993 if ( valid_address ( m68k_getpc () + m68kpc_offset + opwords*2 , 2 ) )
1994 fprintf (f, "%04x ", get_iword_1 (m68kpc_offset + opwords*2));
1995 else
1996 fprintf (f, "**** " );
1997 }
1998 if ( ! valid_address ( m68k_getpc () + m68kpc_offset , 2 ) ) {
1999 fprintf (f , "BUS ERROR\n" ); /* If region is not valid (bus error region) */
2000 m68kpc_offset += 2;
2001 continue;
2002 }
2003
2004 opcode = get_iword_1 (m68kpc_offset);
2005 m68kpc_offset += 2;
2006 if (cpufunctbl[opcode] == op_illg_1) {
2007 opcode = 0x4AFC;
2008 }
2009 dp = table68k + opcode;
2010 for (lookup = lookuptab;lookup->mnemo != dp->mnemo; lookup++)
2011 ;
2012
2013 strcpy (instrname, lookup->name);
2014 ccpt = strstr (instrname, "cc");
2015 if (ccpt != 0) {
2016 strncpy (ccpt, ccnames[dp->cc], 2);
2017 }
2018 fprintf (f, "%s", instrname);
2019 switch (dp->size){
2020 case sz_byte: fprintf (f, ".B "); break;
2021 case sz_word: fprintf (f, ".W "); break;
2022 case sz_long: fprintf (f, ".L "); break;
2023 default: fprintf (f, " "); break;
2024 }
2025
2026 if (dp->suse) {
2027 newpc = m68k_getpc () + m68kpc_offset;
2028 newpc += ShowEA (f, dp->sreg, dp->smode, dp->size, 0);
2029 }
2030 if (dp->suse && dp->duse)
2031 fprintf (f, ",");
2032 if (dp->duse) {
2033 newpc = m68k_getpc () + m68kpc_offset;
2034 newpc += ShowEA (f, dp->dreg, dp->dmode, dp->size, 0);
2035 }
2036 if (ccpt != 0) {
2037 if (cctrue(dp->cc))
2038 fprintf (f, " == %08lx (TRUE)", (long)newpc);
2039 else
2040 fprintf (f, " == %08lx (FALSE)", (long)newpc);
2041 } else if ((opcode & 0xff00) == 0x6100) /* BSR */
2042 fprintf (f, " == %08lx", (long)newpc);
2043 fprintf (f, "\n");
2044 }
2045 if (nextpc)
2046 *nextpc = m68k_getpc () + m68kpc_offset;
2047 }
2048
m68k_dumpstate(FILE * f,uaecptr * nextpc)2049 void m68k_dumpstate (FILE *f, uaecptr *nextpc)
2050 {
2051 int i;
2052 for (i = 0; i < 8; i++){
2053 fprintf (f, "D%d: %08lx ", i, (long)m68k_dreg(regs, i));
2054 if ((i & 3) == 3) fprintf (f, "\n");
2055 }
2056 for (i = 0; i < 8; i++){
2057 fprintf (f, "A%d: %08lx ", i, (long)m68k_areg(regs, i));
2058 if ((i & 3) == 3) fprintf (f, "\n");
2059 }
2060 if (regs.s == 0) regs.usp = m68k_areg(regs, 7);
2061 if (regs.s && regs.m) regs.msp = m68k_areg(regs, 7);
2062 if (regs.s && regs.m == 0) regs.isp = m68k_areg(regs, 7);
2063 fprintf (f, "USP=%08lx ISP=%08lx MSP=%08lx VBR=%08lx\n",
2064 (long)regs.usp,(long)regs.isp,(long)regs.msp,(long)regs.vbr);
2065 fprintf (f, "T=%d%d S=%d M=%d X=%d N=%d Z=%d V=%d C=%d IMASK=%d\n",
2066 regs.t1, regs.t0, regs.s, regs.m,
2067 GET_XFLG, GET_NFLG, GET_ZFLG, GET_VFLG, GET_CFLG, regs.intmask);
2068 for (i = 0; i < 8; i++){
2069 fprintf (f, "FP%d: %g ", i, regs.fp[i]);
2070 if ((i & 3) == 3) fprintf (f, "\n");
2071 }
2072 fprintf (f, "N=%d Z=%d I=%d NAN=%d\n",
2073 (regs.fpsr & 0x8000000) != 0,
2074 (regs.fpsr & 0x4000000) != 0,
2075 (regs.fpsr & 0x2000000) != 0,
2076 (regs.fpsr & 0x1000000) != 0);
2077 if (currprefs.cpu_compatible)
2078 fprintf (f, "prefetch %08lx\n", (unsigned long)do_get_mem_long(®s.prefetch));
2079
2080 m68k_disasm (f, m68k_getpc (), nextpc, 1);
2081 if (nextpc)
2082 fprintf (f, "next PC: %08lx\n", (long)*nextpc);
2083 }
2084
2085
2086 /*
2087
2088 The routines below take dividend and divisor as parameters.
2089 They return 0 if division by zero, or exact number of cycles otherwise.
2090
2091 The number of cycles returned assumes a register operand.
2092 Effective address time must be added if memory operand.
2093
2094 For 68000 only (not 68010, 68012, 68020, etc).
2095 Probably valid for 68008 after adding the extra prefetch cycle.
2096
2097
2098 Best and worst cases are for register operand:
2099 (Note the difference with the documented range.)
2100
2101
2102 DIVU:
2103
2104 Overflow (always): 10 cycles.
2105 Worst case: 136 cycles.
2106 Best case: 76 cycles.
2107
2108
2109 DIVS:
2110
2111 Absolute overflow: 16-18 cycles.
2112 Signed overflow is not detected prematurely.
2113
2114 Worst case: 156 cycles.
2115 Best case without signed overflow: 122 cycles.
2116 Best case with signed overflow: 120 cycles
2117
2118
2119 */
2120
2121
2122 //
2123 // DIVU
2124 // Unsigned division
2125 //
2126
getDivu68kCycles_2(uae_u32 dividend,uae_u16 divisor)2127 STATIC_INLINE int getDivu68kCycles_2 (uae_u32 dividend, uae_u16 divisor)
2128 {
2129 int mcycles;
2130 uae_u32 hdivisor;
2131 int i;
2132
2133 if (divisor == 0)
2134 return 0;
2135
2136 // Overflow
2137 if ((dividend >> 16) >= divisor)
2138 return (mcycles = 5) * 2;
2139
2140 mcycles = 38;
2141 hdivisor = divisor << 16;
2142
2143 for (i = 0; i < 15; i++) {
2144 uae_u32 temp;
2145 temp = dividend;
2146
2147 dividend <<= 1;
2148
2149 // If carry from shift
2150 if ((uae_s32)temp < 0)
2151 dividend -= hdivisor;
2152 else {
2153 mcycles += 2;
2154 if (dividend >= hdivisor) {
2155 dividend -= hdivisor;
2156 mcycles--;
2157 }
2158 }
2159 }
2160 return mcycles * 2;
2161 }
getDivu68kCycles(uae_u32 dividend,uae_u16 divisor)2162 int getDivu68kCycles (uae_u32 dividend, uae_u16 divisor)
2163 {
2164 int v = getDivu68kCycles_2 (dividend, divisor) - 4;
2165 // write_log ("U%d ", v);
2166 return v;
2167 }
2168
2169 //
2170 // DIVS
2171 // Signed division
2172 //
2173
getDivs68kCycles_2(uae_s32 dividend,uae_s16 divisor)2174 STATIC_INLINE int getDivs68kCycles_2 (uae_s32 dividend, uae_s16 divisor)
2175 {
2176 int mcycles;
2177 uae_u32 aquot;
2178 int i;
2179
2180 if (divisor == 0)
2181 return 0;
2182
2183 mcycles = 6;
2184
2185 if (dividend < 0)
2186 mcycles++;
2187
2188 // Check for absolute overflow
2189 if (((uae_u32)abs (dividend) >> 16) >= (uae_u16)abs (divisor))
2190 return (mcycles + 2) * 2;
2191
2192 // Absolute quotient
2193 aquot = (uae_u32) abs (dividend) / (uae_u16)abs (divisor);
2194
2195 mcycles += 55;
2196
2197 if (divisor >= 0) {
2198 if (dividend >= 0)
2199 mcycles--;
2200 else
2201 mcycles++;
2202 }
2203
2204 // Count 15 msbits in absolute of quotient
2205
2206 for (i = 0; i < 15; i++) {
2207 if ((uae_s16)aquot >= 0)
2208 mcycles++;
2209 aquot <<= 1;
2210 }
2211
2212 return mcycles * 2;
2213 }
getDivs68kCycles(uae_s32 dividend,uae_s16 divisor)2214 int getDivs68kCycles (uae_s32 dividend, uae_s16 divisor)
2215 {
2216 int v = getDivs68kCycles_2 (dividend, divisor) - 4;
2217 // write_log ("S%d ", v);
2218 return v;
2219 }
2220