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 // Handle exceptions. We need a special case to handle MFP exceptions
102 // on Atari ST, because it's possible to change the MFP's vector base
103 // and get a conflict with 'normal' cpu exceptions.
105 void Exception(int nr, uint32_t oldpc, int ExceptionSource)
107 printf("Exception #%i occurred!\n", nr);
108 printf("Vector @ #%i = %08X\n", nr, m68k_read_memory_32(nr * 4));
110 uint32_t currpc = m68k_getpc(), newpc;
112 /*if( nr>=2 && nr<10 ) fprintf(stderr,"Exception (-> %i bombs)!\n",nr);*/
116 // Change to supervisor mode if necessary
119 regs.usp = m68k_areg(regs, 7);
120 m68k_areg(regs, 7) = regs.isp;
124 // Create 68000 style stack frame
125 m68k_areg(regs, 7) -= 4; // Push PC on stack
126 m68k_write_memory_32(m68k_areg(regs, 7), currpc);
127 m68k_areg(regs, 7) -= 2; // Push SR on stack
128 m68k_write_memory_16(m68k_areg(regs, 7), regs.sr);
130 // LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x\n",
131 // nr, currpc, BusErrorPC, get_long(4 * nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3);
134 /* 68000 bus/address errors: */
135 if ((nr == 2 || nr == 3) && ExceptionSource == M68000_EXC_SRC_CPU)
137 uint16_t specialstatus = 1;
139 /* Special status word emulation isn't perfect yet... :-( */
140 if (regs.sr & 0x2000)
141 specialstatus |= 0x4;
143 m68k_areg(regs, 7) -= 8;
145 if (nr == 3) /* Address error */
147 specialstatus |= (last_op_for_exception_3 & (~0x1F)); /* [NP] unused bits of specialstatus are those of the last opcode ! */
148 put_word(m68k_areg(regs, 7), specialstatus);
149 put_long(m68k_areg(regs, 7) + 2, last_fault_for_exception_3);
150 put_word(m68k_areg(regs, 7) + 6, last_op_for_exception_3);
151 put_long(m68k_areg(regs, 7) + 10, last_addr_for_exception_3);
155 if (bExceptionDebugging)
157 fprintf(stderr,"Address Error at address $%x, PC=$%x\n", last_fault_for_exception_3, currpc);
164 specialstatus |= (get_word(BusErrorPC) & (~0x1F)); /* [NP] unused bits of special status are those of the last opcode ! */
166 if (bBusErrorReadWrite)
167 specialstatus |= 0x10;
169 put_word(m68k_areg(regs, 7), specialstatus);
170 put_long(m68k_areg(regs, 7) + 2, BusErrorAddress);
171 put_word(m68k_areg(regs, 7) + 6, get_word(BusErrorPC)); /* Opcode */
173 /* [NP] PC stored in the stack frame is not necessarily pointing to the next instruction ! */
174 /* FIXME : we should have a proper model for this, in the meantime we handle specific cases */
175 if (get_word(BusErrorPC) == 0x21F8) /* move.l $0.w,$24.w (Transbeauce 2 loader) */
176 put_long(m68k_areg(regs, 7) + 10, currpc - 2); /* correct PC is 2 bytes less than usual value */
178 /* Check for double bus errors: */
179 if (regs.spcflags & SPCFLAG_BUSERROR)
181 fprintf(stderr, "Detected double bus error at address $%x, PC=$%lx => CPU halted!\n",
182 BusErrorAddress, (long)currpc);
183 unset_special(SPCFLAG_BUSERROR);
185 if (bExceptionDebugging)
188 DlgAlert_Notice("Detected double bus error => CPU halted!\nEmulation needs to be reset.\n");
191 m68k_setstopped(true);
195 if (bExceptionDebugging && BusErrorAddress != 0xFF8A00)
197 fprintf(stderr,"Bus Error at address $%x, PC=$%lx\n", BusErrorAddress, (long)currpc);
205 /* Set PC and flags */
206 if (bExceptionDebugging && get_long(4 * nr) == 0)
208 write_log("Uninitialized exception handler #%i!\n", nr);
213 newpc = get_long(4 * nr);
215 if (newpc & 1) /* check new pc is odd */
217 if (nr == 2 || nr == 3) /* address error during bus/address error -> stop emulation */
219 fprintf(stderr,"Address Error during exception 2/3, aborting new PC=$%x\n", newpc);
224 fprintf(stderr,"Address Error during exception, new PC=$%x\n", newpc);
225 Exception(3, m68k_getpc(), M68000_EXC_SRC_CPU);
232 m68k_setpc(m68k_read_memory_32(4 * nr));
234 /* Handle trace flags depending on current state */
235 //JLH:no exception_trace(nr);
238 /* Handle exception cycles (special case for MFP) */
239 // if (ExceptionSource == M68000_EXC_SRC_INT_MFP)
241 // M68000_AddCycles(44 + 12); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */
244 if (nr >= 24 && nr <= 31)
247 if (nr == 26) /* HBL */
249 /* store current cycle pos when then interrupt was received (see video.c) */
250 LastCycleHblException = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
251 M68000_AddCycles(44 + 12); /* Video Interrupt */
253 else if (nr == 28) /* VBL */
254 M68000_AddCycles(44 + 12); /* Video Interrupt */
257 M68000_AddCycles(44 + 4); /* Other Interrupts */
259 else if (nr >= 32 && nr <= 47)
261 M68000_AddCycles(34 - 4); /* Trap (total is 34, but cpuemu.c already adds 4) */
265 case 2: M68000_AddCycles(50); break; /* Bus error */
266 case 3: M68000_AddCycles(50); break; /* Address error */
267 case 4: M68000_AddCycles(34); break; /* Illegal instruction */
268 case 5: M68000_AddCycles(38); break; /* Div by zero */
269 case 6: M68000_AddCycles(40); break; /* CHK */
270 case 7: M68000_AddCycles(34); break; /* TRAPV */
271 case 8: M68000_AddCycles(34); break; /* Privilege violation */
272 case 9: M68000_AddCycles(34); break; /* Trace */
273 case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */
274 case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */
276 /* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */
278 M68000_AddCycles(4); /* Coprocessor and unassigned exceptions (???) */
280 M68000_AddCycles(44 + 12); /* Must be a MFP or DSP interrupt */
288 The routines below take dividend and divisor as parameters.
289 They return 0 if division by zero, or exact number of cycles otherwise.
291 The number of cycles returned assumes a register operand.
292 Effective address time must be added if memory operand.
294 For 68000 only (not 68010, 68012, 68020, etc).
295 Probably valid for 68008 after adding the extra prefetch cycle.
298 Best and worst cases are for register operand:
299 (Note the difference with the documented range.)
304 Overflow (always): 10 cycles.
305 Worst case: 136 cycles.
306 Best case: 76 cycles.
311 Absolute overflow: 16-18 cycles.
312 Signed overflow is not detected prematurely.
314 Worst case: 156 cycles.
315 Best case without signed overflow: 122 cycles.
316 Best case with signed overflow: 120 cycles
323 STATIC_INLINE int getDivu68kCycles_2 (uint32_t dividend, uint16_t divisor)
333 if ((dividend >> 16) >= divisor)
334 return (mcycles = 5) * 2;
337 hdivisor = divisor << 16;
346 // If carry from shift
347 if ((int32_t)temp < 0)
348 dividend -= hdivisor;
353 if (dividend >= hdivisor)
355 dividend -= hdivisor;
364 // This is called by cpuemu.c
365 int getDivu68kCycles(uint32_t dividend, uint16_t divisor)
367 int v = getDivu68kCycles_2(dividend, divisor) - 4;
368 // write_log ("U%d ", v);
377 STATIC_INLINE int getDivs68kCycles_2(int32_t dividend, int16_t divisor)
391 // Check for absolute overflow
392 if (((uint32_t)abs(dividend) >> 16) >= (uint16_t)abs(divisor))
393 return (mcycles + 2) * 2;
396 aquot = (uint32_t)abs(dividend) / (uint16_t)abs(divisor);
408 // Count 15 msbits in absolute of quotient
412 if ((int16_t)aquot >= 0)
421 // This is called by cpuemu.c
422 int getDivs68kCycles(int32_t dividend, int16_t divisor)
424 int v = getDivs68kCycles_2(dividend, divisor) - 4;
425 // write_log ("S%d ", v);