2 // Stuff that's neither inline or generated by gencpu.c, but depended upon by
5 // Originally part of UAE by Bernd Schmidt
6 // and released under the GPL v2 or later
14 uint16_t last_op_for_exception_3; // Opcode of faulting instruction
15 uint32_t last_addr_for_exception_3; // PC at fault time
16 uint32_t last_fault_for_exception_3; // Address that generated the exception
18 int OpcodeFamily; // Used by cpuemu.c...
19 int BusCyclePenalty = 0; // Used by cpuemu.c...
20 int CurrentInstrCycles;
22 struct regstruct regs;
26 // Make displacement effective address for 68000
28 uint32_t get_disp_ea_000(uint32_t base, uint32_t dp)
30 int reg = (dp >> 12) & 0x0F;
31 int32_t regd = regs.regs[reg];
34 if ((dp & 0x800) == 0)
35 regd = (int32_t)(int16_t)regd;
37 return base + (int8_t)dp + regd;
39 /* Branch-free code... benchmark this again now that
40 * things are no longer inline.
44 mask = ((dp & 0x800) >> 11) - 1;
45 regd16 = (int32_t)(int16_t)regd;
57 // Create the Status Register from the flags
61 regs.sr = ((regs.s << 13) | (regs.intmask << 8) | (GET_XFLG << 4)
62 | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1) | GET_CFLG);
67 // Set up the flags from Status Register
73 regs.s = (regs.sr >> 13) & 1;
74 regs.intmask = (regs.sr >> 8) & 7;
75 SET_XFLG((regs.sr >> 4) & 1);
76 SET_NFLG((regs.sr >> 3) & 1);
77 SET_ZFLG((regs.sr >> 2) & 1);
78 SET_VFLG((regs.sr >> 1) & 1);
79 SET_CFLG(regs.sr & 1);
85 regs.isp = m68k_areg(regs, 7);
86 m68k_areg(regs, 7) = regs.usp;
90 regs.usp = m68k_areg(regs, 7);
91 m68k_areg(regs, 7) = regs.isp;
95 /* Pending interrupts can occur again after a write to the SR: */
96 //JLH: is this needed?
97 // set_special(SPCFLAG_DOINT);
102 // Rudimentary exception handling. This is really stripped down from what
105 NB: Seems that when an address exception occurs, it doesn't get handled properly
106 as per test1.cof. Need to figure out why it keeps going when it should wedge. :-P
109 // Handle exceptions. We need a special case to handle MFP exceptions
110 // on Atari ST, because it's possible to change the MFP's vector base
111 // and get a conflict with 'normal' cpu exceptions.
113 void Exception(int nr, uint32_t oldpc, int ExceptionSource)
115 uint32_t currpc = m68k_getpc(), newpc;
117 // Need to figure out how to report this stuff without using printf on stdout :-/
119 char excNames[33][64] = {
120 "???", "???", "Bus Error", "Address Error",
121 "Illegal Instruction", "Zero Divide", "CHK", "TrapV",
122 "Privilege Violation", "Trace", "Line A", "Line F",
123 "???", "???", "Format Error", "Uninitialized Interrupt",
124 "???", "???", "???", "???",
125 "???", "???", "???", "???",
126 "Spurious/Autovector", "???", "???", "???",
127 "???", "???", "???", "???",
131 printf("Exception #%i occurred! (%s)\n", nr, (nr < 32 ? excNames[nr] : (nr < 48 ? "Trap #" : "????")));
132 printf("Vector @ #%i = %08X\n", nr, m68k_read_memory_32(nr * 4));
134 printf("PC = $%08X\n", currpc);
135 printf("A0 = $%08X A1 = $%08X A2 = $%08X A3 = $%08X\n", m68k_areg(regs, 0), m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_areg(regs, 3));
136 printf("A4 = $%08X A5 = $%08X A6 = $%08X A7 = $%08X\n", m68k_areg(regs, 4), m68k_areg(regs, 5), m68k_areg(regs, 6), m68k_areg(regs, 7));
137 printf("D0 = $%08X D1 = $%08X D2 = $%08X D3 = $%08X\n", m68k_dreg(regs, 0), m68k_dreg(regs, 1), m68k_dreg(regs, 2), m68k_dreg(regs, 3));
138 printf("D4 = $%08X D5 = $%08X D6 = $%08X D7 = $%08X\n", m68k_dreg(regs, 4), m68k_dreg(regs, 5), m68k_dreg(regs, 6), m68k_dreg(regs, 7));
141 uint32_t disPC = currpc - 10;
146 uint32_t oldpc = disPC;
147 disPC += m68k_disassemble(buffer, disPC, 0);
148 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
150 while (disPC < (currpc + 10));
153 /*if( nr>=2 && nr<10 ) fprintf(stderr,"Exception (-> %i bombs)!\n",nr);*/
157 // Change to supervisor mode if necessary
160 regs.usp = m68k_areg(regs, 7);
161 m68k_areg(regs, 7) = regs.isp;
165 // Create 68000 style stack frame
166 m68k_areg(regs, 7) -= 4; // Push PC on stack
167 m68k_write_memory_32(m68k_areg(regs, 7), currpc);
168 m68k_areg(regs, 7) -= 2; // Push SR on stack
169 m68k_write_memory_16(m68k_areg(regs, 7), regs.sr);
171 // LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x\n",
172 // nr, currpc, BusErrorPC, get_long(4 * nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3);
175 /* 68000 bus/address errors: */
176 if ((nr == 2 || nr == 3) && ExceptionSource == M68000_EXC_SRC_CPU)
178 uint16_t specialstatus = 1;
180 /* Special status word emulation isn't perfect yet... :-( */
181 if (regs.sr & 0x2000)
182 specialstatus |= 0x4;
184 m68k_areg(regs, 7) -= 8;
186 if (nr == 3) /* Address error */
188 specialstatus |= (last_op_for_exception_3 & (~0x1F)); /* [NP] unused bits of specialstatus are those of the last opcode ! */
189 put_word(m68k_areg(regs, 7), specialstatus);
190 put_long(m68k_areg(regs, 7) + 2, last_fault_for_exception_3);
191 put_word(m68k_areg(regs, 7) + 6, last_op_for_exception_3);
192 put_long(m68k_areg(regs, 7) + 10, last_addr_for_exception_3);
196 if (bExceptionDebugging)
198 fprintf(stderr,"Address Error at address $%x, PC=$%x\n", last_fault_for_exception_3, currpc);
205 specialstatus |= (get_word(BusErrorPC) & (~0x1F)); /* [NP] unused bits of special status are those of the last opcode ! */
207 if (bBusErrorReadWrite)
208 specialstatus |= 0x10;
210 put_word(m68k_areg(regs, 7), specialstatus);
211 put_long(m68k_areg(regs, 7) + 2, BusErrorAddress);
212 put_word(m68k_areg(regs, 7) + 6, get_word(BusErrorPC)); /* Opcode */
214 /* [NP] PC stored in the stack frame is not necessarily pointing to the next instruction ! */
215 /* FIXME : we should have a proper model for this, in the meantime we handle specific cases */
216 if (get_word(BusErrorPC) == 0x21F8) /* move.l $0.w,$24.w (Transbeauce 2 loader) */
217 put_long(m68k_areg(regs, 7) + 10, currpc - 2); /* correct PC is 2 bytes less than usual value */
219 /* Check for double bus errors: */
220 if (regs.spcflags & SPCFLAG_BUSERROR)
222 fprintf(stderr, "Detected double bus error at address $%x, PC=$%lx => CPU halted!\n",
223 BusErrorAddress, (long)currpc);
224 unset_special(SPCFLAG_BUSERROR);
226 if (bExceptionDebugging)
229 DlgAlert_Notice("Detected double bus error => CPU halted!\nEmulation needs to be reset.\n");
232 m68k_setstopped(true);
236 if (bExceptionDebugging && BusErrorAddress != 0xFF8A00)
238 fprintf(stderr,"Bus Error at address $%x, PC=$%lx\n", BusErrorAddress, (long)currpc);
246 /* Set PC and flags */
247 if (bExceptionDebugging && get_long(4 * nr) == 0)
249 write_log("Uninitialized exception handler #%i!\n", nr);
254 newpc = get_long(4 * nr);
256 if (newpc & 1) /* check new pc is odd */
258 if (nr == 2 || nr == 3) /* address error during bus/address error -> stop emulation */
260 fprintf(stderr,"Address Error during exception 2/3, aborting new PC=$%x\n", newpc);
265 fprintf(stderr,"Address Error during exception, new PC=$%x\n", newpc);
266 Exception(3, m68k_getpc(), M68000_EXC_SRC_CPU);
273 m68k_setpc(m68k_read_memory_32(4 * nr));
275 /* Handle trace flags depending on current state */
276 //JLH:no exception_trace(nr);
279 /* Handle exception cycles (special case for MFP) */
280 // if (ExceptionSource == M68000_EXC_SRC_INT_MFP)
282 // M68000_AddCycles(44 + 12); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */
285 if (nr >= 24 && nr <= 31)
288 if (nr == 26) /* HBL */
290 /* store current cycle pos when then interrupt was received (see video.c) */
291 LastCycleHblException = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
292 M68000_AddCycles(44 + 12); /* Video Interrupt */
294 else if (nr == 28) /* VBL */
295 M68000_AddCycles(44 + 12); /* Video Interrupt */
298 M68000_AddCycles(44 + 4); /* Other Interrupts */
300 else if (nr >= 32 && nr <= 47)
302 M68000_AddCycles(34 - 4); /* Trap (total is 34, but cpuemu.c already adds 4) */
306 case 2: M68000_AddCycles(50); break; /* Bus error */
307 case 3: M68000_AddCycles(50); break; /* Address error */
308 case 4: M68000_AddCycles(34); break; /* Illegal instruction */
309 case 5: M68000_AddCycles(38); break; /* Div by zero */
310 case 6: M68000_AddCycles(40); break; /* CHK */
311 case 7: M68000_AddCycles(34); break; /* TRAPV */
312 case 8: M68000_AddCycles(34); break; /* Privilege violation */
313 case 9: M68000_AddCycles(34); break; /* Trace */
314 case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */
315 case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */
317 /* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */
319 M68000_AddCycles(4); /* Coprocessor and unassigned exceptions (???) */
321 M68000_AddCycles(44 + 12); /* Must be a MFP or DSP interrupt */
330 The routines below take dividend and divisor as parameters.
331 They return 0 if division by zero, or exact number of cycles otherwise.
333 The number of cycles returned assumes a register operand.
334 Effective address time must be added if memory operand.
336 For 68000 only (not 68010, 68012, 68020, etc).
337 Probably valid for 68008 after adding the extra prefetch cycle.
340 Best and worst cases are for register operand:
341 (Note the difference with the documented range.)
346 Overflow (always): 10 cycles.
347 Worst case: 136 cycles.
348 Best case: 76 cycles.
353 Absolute overflow: 16-18 cycles.
354 Signed overflow is not detected prematurely.
356 Worst case: 156 cycles.
357 Best case without signed overflow: 122 cycles.
358 Best case with signed overflow: 120 cycles
365 STATIC_INLINE int getDivu68kCycles_2 (uint32_t dividend, uint16_t divisor)
375 if ((dividend >> 16) >= divisor)
376 return (mcycles = 5) * 2;
379 hdivisor = divisor << 16;
388 // If carry from shift
389 if ((int32_t)temp < 0)
390 dividend -= hdivisor;
395 if (dividend >= hdivisor)
397 dividend -= hdivisor;
407 // This is called by cpuemu.c
408 int getDivu68kCycles(uint32_t dividend, uint16_t divisor)
410 int v = getDivu68kCycles_2(dividend, divisor) - 4;
411 // write_log ("U%d ", v);
420 STATIC_INLINE int getDivs68kCycles_2(int32_t dividend, int16_t divisor)
434 // Check for absolute overflow
435 if (((uint32_t)abs(dividend) >> 16) >= (uint16_t)abs(divisor))
436 return (mcycles + 2) * 2;
439 aquot = (uint32_t)abs(dividend) / (uint16_t)abs(divisor);
451 // Count 15 msbits in absolute of quotient
455 if ((int16_t)aquot >= 0)
465 // This is called by cpuemu.c
466 int getDivs68kCycles(int32_t dividend, int16_t divisor)
468 int v = getDivs68kCycles_2(dividend, divisor) - 4;
469 // write_log ("S%d ", v);