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;
25 // Make displacement effective address for 68000
27 uint32_t get_disp_ea_000(uint32_t base, uint32_t dp)
29 int reg = (dp >> 12) & 0x0F;
30 int32_t regd = regs.regs[reg];
33 if ((dp & 0x800) == 0)
34 regd = (int32_t)(int16_t)regd;
36 return base + (int8_t)dp + regd;
38 /* Branch-free code... benchmark this again now that
39 * things are no longer inline.
43 mask = ((dp & 0x800) >> 11) - 1;
44 regd16 = (int32_t)(int16_t)regd;
55 // Create the Status Register from the flags
59 regs.sr = ((regs.s << 13) | (regs.intmask << 8) | (GET_XFLG << 4)
60 | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1) | GET_CFLG);
64 // Set up the flags from Status Register
70 regs.s = (regs.sr >> 13) & 1;
71 regs.intmask = (regs.sr >> 8) & 7;
72 SET_XFLG((regs.sr >> 4) & 1);
73 SET_NFLG((regs.sr >> 3) & 1);
74 SET_ZFLG((regs.sr >> 2) & 1);
75 SET_VFLG((regs.sr >> 1) & 1);
76 SET_CFLG(regs.sr & 1);
82 regs.isp = m68k_areg(regs, 7);
83 m68k_areg(regs, 7) = regs.usp;
87 regs.usp = m68k_areg(regs, 7);
88 m68k_areg(regs, 7) = regs.isp;
92 /* Pending interrupts can occur again after a write to the SR: */
93 //JLH: is this needed?
94 // set_special(SPCFLAG_DOINT);
98 // Rudimentary exception handling. This is really stripped down from what
101 NB: Seems that when an address exception occurs, it doesn't get handled properly
102 as per test1.cof. Need to figure out why it keeps going when it should wedge. :-P
105 // Handle exceptions. We need a special case to handle MFP exceptions
106 // on Atari ST, because it's possible to change the MFP's vector base
107 // and get a conflict with 'normal' cpu exceptions.
109 void Exception(int nr, uint32_t oldpc, int ExceptionSource)
111 char excNames[33][64] = {
112 "???", "???", "Bus Error", "Address Error",
113 "Illegal Instruction", "Zero Divide", "CHK", "TrapV",
114 "Privilege Violation", "Trace", "Line A", "Line F",
115 "???", "???", "Format Error", "Uninitialized Interrupt",
116 "???", "???", "???", "???",
117 "???", "???", "???", "???",
118 "Spurious/Autovector", "???", "???", "???",
119 "???", "???", "???", "???",
123 printf("Exception #%i occurred! (%s)\n", nr, (nr < 32 ? excNames[nr] : (nr < 48 ? "Trap #" : "????")));
124 printf("Vector @ #%i = %08X\n", nr, m68k_read_memory_32(nr * 4));
126 uint32_t currpc = m68k_getpc(), newpc;
127 printf("PC = $%08X\n", currpc);
128 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));
129 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));
130 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));
131 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));
134 uint32_t disPC = currpc - 10;
139 uint32_t oldpc = disPC;
140 disPC += m68k_disassemble(buffer, disPC, 0);
141 printf("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
143 while (disPC < (currpc + 10));
145 /*if( nr>=2 && nr<10 ) fprintf(stderr,"Exception (-> %i bombs)!\n",nr);*/
149 // Change to supervisor mode if necessary
152 regs.usp = m68k_areg(regs, 7);
153 m68k_areg(regs, 7) = regs.isp;
157 // Create 68000 style stack frame
158 m68k_areg(regs, 7) -= 4; // Push PC on stack
159 m68k_write_memory_32(m68k_areg(regs, 7), currpc);
160 m68k_areg(regs, 7) -= 2; // Push SR on stack
161 m68k_write_memory_16(m68k_areg(regs, 7), regs.sr);
163 // LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x\n",
164 // nr, currpc, BusErrorPC, get_long(4 * nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3);
167 /* 68000 bus/address errors: */
168 if ((nr == 2 || nr == 3) && ExceptionSource == M68000_EXC_SRC_CPU)
170 uint16_t specialstatus = 1;
172 /* Special status word emulation isn't perfect yet... :-( */
173 if (regs.sr & 0x2000)
174 specialstatus |= 0x4;
176 m68k_areg(regs, 7) -= 8;
178 if (nr == 3) /* Address error */
180 specialstatus |= (last_op_for_exception_3 & (~0x1F)); /* [NP] unused bits of specialstatus are those of the last opcode ! */
181 put_word(m68k_areg(regs, 7), specialstatus);
182 put_long(m68k_areg(regs, 7) + 2, last_fault_for_exception_3);
183 put_word(m68k_areg(regs, 7) + 6, last_op_for_exception_3);
184 put_long(m68k_areg(regs, 7) + 10, last_addr_for_exception_3);
188 if (bExceptionDebugging)
190 fprintf(stderr,"Address Error at address $%x, PC=$%x\n", last_fault_for_exception_3, currpc);
197 specialstatus |= (get_word(BusErrorPC) & (~0x1F)); /* [NP] unused bits of special status are those of the last opcode ! */
199 if (bBusErrorReadWrite)
200 specialstatus |= 0x10;
202 put_word(m68k_areg(regs, 7), specialstatus);
203 put_long(m68k_areg(regs, 7) + 2, BusErrorAddress);
204 put_word(m68k_areg(regs, 7) + 6, get_word(BusErrorPC)); /* Opcode */
206 /* [NP] PC stored in the stack frame is not necessarily pointing to the next instruction ! */
207 /* FIXME : we should have a proper model for this, in the meantime we handle specific cases */
208 if (get_word(BusErrorPC) == 0x21F8) /* move.l $0.w,$24.w (Transbeauce 2 loader) */
209 put_long(m68k_areg(regs, 7) + 10, currpc - 2); /* correct PC is 2 bytes less than usual value */
211 /* Check for double bus errors: */
212 if (regs.spcflags & SPCFLAG_BUSERROR)
214 fprintf(stderr, "Detected double bus error at address $%x, PC=$%lx => CPU halted!\n",
215 BusErrorAddress, (long)currpc);
216 unset_special(SPCFLAG_BUSERROR);
218 if (bExceptionDebugging)
221 DlgAlert_Notice("Detected double bus error => CPU halted!\nEmulation needs to be reset.\n");
224 m68k_setstopped(true);
228 if (bExceptionDebugging && BusErrorAddress != 0xFF8A00)
230 fprintf(stderr,"Bus Error at address $%x, PC=$%lx\n", BusErrorAddress, (long)currpc);
238 /* Set PC and flags */
239 if (bExceptionDebugging && get_long(4 * nr) == 0)
241 write_log("Uninitialized exception handler #%i!\n", nr);
246 newpc = get_long(4 * nr);
248 if (newpc & 1) /* check new pc is odd */
250 if (nr == 2 || nr == 3) /* address error during bus/address error -> stop emulation */
252 fprintf(stderr,"Address Error during exception 2/3, aborting new PC=$%x\n", newpc);
257 fprintf(stderr,"Address Error during exception, new PC=$%x\n", newpc);
258 Exception(3, m68k_getpc(), M68000_EXC_SRC_CPU);
265 m68k_setpc(m68k_read_memory_32(4 * nr));
267 /* Handle trace flags depending on current state */
268 //JLH:no exception_trace(nr);
271 /* Handle exception cycles (special case for MFP) */
272 // if (ExceptionSource == M68000_EXC_SRC_INT_MFP)
274 // M68000_AddCycles(44 + 12); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */
277 if (nr >= 24 && nr <= 31)
280 if (nr == 26) /* HBL */
282 /* store current cycle pos when then interrupt was received (see video.c) */
283 LastCycleHblException = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
284 M68000_AddCycles(44 + 12); /* Video Interrupt */
286 else if (nr == 28) /* VBL */
287 M68000_AddCycles(44 + 12); /* Video Interrupt */
290 M68000_AddCycles(44 + 4); /* Other Interrupts */
292 else if (nr >= 32 && nr <= 47)
294 M68000_AddCycles(34 - 4); /* Trap (total is 34, but cpuemu.c already adds 4) */
298 case 2: M68000_AddCycles(50); break; /* Bus error */
299 case 3: M68000_AddCycles(50); break; /* Address error */
300 case 4: M68000_AddCycles(34); break; /* Illegal instruction */
301 case 5: M68000_AddCycles(38); break; /* Div by zero */
302 case 6: M68000_AddCycles(40); break; /* CHK */
303 case 7: M68000_AddCycles(34); break; /* TRAPV */
304 case 8: M68000_AddCycles(34); break; /* Privilege violation */
305 case 9: M68000_AddCycles(34); break; /* Trace */
306 case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */
307 case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */
309 /* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */
311 M68000_AddCycles(4); /* Coprocessor and unassigned exceptions (???) */
313 M68000_AddCycles(44 + 12); /* Must be a MFP or DSP interrupt */
321 The routines below take dividend and divisor as parameters.
322 They return 0 if division by zero, or exact number of cycles otherwise.
324 The number of cycles returned assumes a register operand.
325 Effective address time must be added if memory operand.
327 For 68000 only (not 68010, 68012, 68020, etc).
328 Probably valid for 68008 after adding the extra prefetch cycle.
331 Best and worst cases are for register operand:
332 (Note the difference with the documented range.)
337 Overflow (always): 10 cycles.
338 Worst case: 136 cycles.
339 Best case: 76 cycles.
344 Absolute overflow: 16-18 cycles.
345 Signed overflow is not detected prematurely.
347 Worst case: 156 cycles.
348 Best case without signed overflow: 122 cycles.
349 Best case with signed overflow: 120 cycles
356 STATIC_INLINE int getDivu68kCycles_2 (uint32_t dividend, uint16_t divisor)
366 if ((dividend >> 16) >= divisor)
367 return (mcycles = 5) * 2;
370 hdivisor = divisor << 16;
379 // If carry from shift
380 if ((int32_t)temp < 0)
381 dividend -= hdivisor;
386 if (dividend >= hdivisor)
388 dividend -= hdivisor;
397 // This is called by cpuemu.c
398 int getDivu68kCycles(uint32_t dividend, uint16_t divisor)
400 int v = getDivu68kCycles_2(dividend, divisor) - 4;
401 // write_log ("U%d ", v);
410 STATIC_INLINE int getDivs68kCycles_2(int32_t dividend, int16_t divisor)
424 // Check for absolute overflow
425 if (((uint32_t)abs(dividend) >> 16) >= (uint16_t)abs(divisor))
426 return (mcycles + 2) * 2;
429 aquot = (uint32_t)abs(dividend) / (uint16_t)abs(divisor);
441 // Count 15 msbits in absolute of quotient
445 if ((int16_t)aquot >= 0)
454 // This is called by cpuemu.c
455 int getDivs68kCycles(int32_t dividend, int16_t divisor)
457 int v = getDivs68kCycles_2(dividend, divisor) - 4;
458 // write_log ("S%d ", v);