1 //
2 // Stuff that's neither inline or generated by gencpu.c, but depended upon by
3 // cpuemu.c.
4 //
5 // Originally part of UAE by Bernd Schmidt
6 // and released under the GPL v2 or later
7 //
8
9 #include "cpuextra.h"
10 #include "cpudefs.h"
11 #include "inlines.h"
12
13
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
17
18 int OpcodeFamily; // Used by cpuemu.c...
19 int BusCyclePenalty = 0; // Used by cpuemu.c...
20 int CurrentInstrCycles;
21
22 struct regstruct regs;
23
24
25 //
26 // Make displacement effective address for 68000
27 //
get_disp_ea_000(uint32_t base,uint32_t dp)28 uint32_t get_disp_ea_000(uint32_t base, uint32_t dp)
29 {
30 int reg = (dp >> 12) & 0x0F;
31 int32_t regd = regs.regs[reg];
32
33 if ((dp & 0x800) == 0)
34 regd = (int32_t)(int16_t)regd;
35
36 return base + (int8_t)dp + regd;
37 }
38
39
40 //
41 // Create the Status Register from the flags
42 //
MakeSR(void)43 void MakeSR(void)
44 {
45 regs.sr = ((regs.s << 13) | (regs.intmask << 8) | (GET_XFLG << 4)
46 | (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1) | GET_CFLG);
47 }
48
49
50 //
51 // Set up the flags from Status Register
52 //
MakeFromSR(void)53 void MakeFromSR(void)
54 {
55 int olds = regs.s;
56
57 regs.s = (regs.sr >> 13) & 1;
58 regs.intmask = (regs.sr >> 8) & 7;
59 SET_XFLG((regs.sr >> 4) & 1);
60 SET_NFLG((regs.sr >> 3) & 1);
61 SET_ZFLG((regs.sr >> 2) & 1);
62 SET_VFLG((regs.sr >> 1) & 1);
63 SET_CFLG(regs.sr & 1);
64
65 if (olds != regs.s)
66 {
67 if (olds)
68 {
69 regs.isp = m68k_areg(regs, 7);
70 m68k_areg(regs, 7) = regs.usp;
71 }
72 else
73 {
74 regs.usp = m68k_areg(regs, 7);
75 m68k_areg(regs, 7) = regs.isp;
76 }
77 }
78
79 /* Pending interrupts can occur again after a write to the SR: */
80 //JLH: is this needed?
81 // set_special(SPCFLAG_DOINT);
82 }
83
84
85 //
86 // Rudimentary exception handling. This is really stripped down from what
87 // was in Hatari.
88 /*
89 NB: Seems that when an address exception occurs, it doesn't get handled properly
90 as per test1.cof. Need to figure out why it keeps going when it should wedge. :-P
91 */
92 //
93 // Handle exceptions. We need a special case to handle MFP exceptions
94 // on Atari ST, because it's possible to change the MFP's vector base
95 // and get a conflict with 'normal' cpu exceptions.
96 //
Exception(int nr,uint32_t oldpc,int ExceptionSource)97 void Exception(int nr, uint32_t oldpc, int ExceptionSource)
98 {
99 uint32_t currpc = m68k_getpc(), newpc;
100
101 MakeSR();
102
103 // Change to supervisor mode if necessary
104 if (!regs.s)
105 {
106 regs.usp = m68k_areg(regs, 7);
107 m68k_areg(regs, 7) = regs.isp;
108 regs.s = 1;
109 }
110
111 // Create 68000 style stack frame
112 m68k_areg(regs, 7) -= 4; // Push PC on stack
113 m68k_write_memory_32(m68k_areg(regs, 7), currpc);
114 m68k_areg(regs, 7) -= 2; // Push SR on stack
115 m68k_write_memory_16(m68k_areg(regs, 7), regs.sr);
116
117 // LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x\n",
118 // nr, currpc, BusErrorPC, get_long(4 * nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3);
119
120 m68k_setpc(m68k_read_memory_32(4 * nr));
121 fill_prefetch_0();
122 /* Handle trace flags depending on current state */
123 }
124
125
126 /*
127 The routines below take dividend and divisor as parameters.
128 They return 0 if division by zero, or exact number of cycles otherwise.
129
130 The number of cycles returned assumes a register operand.
131 Effective address time must be added if memory operand.
132
133 For 68000 only (not 68010, 68012, 68020, etc).
134 Probably valid for 68008 after adding the extra prefetch cycle.
135
136
137 Best and worst cases are for register operand:
138 (Note the difference with the documented range.)
139
140
141 DIVU:
142
143 Overflow (always): 10 cycles.
144 Worst case: 136 cycles.
145 Best case: 76 cycles.
146
147
148 DIVS:
149
150 Absolute overflow: 16-18 cycles.
151 Signed overflow is not detected prematurely.
152
153 Worst case: 156 cycles.
154 Best case without signed overflow: 122 cycles.
155 Best case with signed overflow: 120 cycles
156 */
157
158 //
159 // DIVU
160 // Unsigned division
161 //
getDivu68kCycles_2(uint32_t dividend,uint16_t divisor)162 static INLINE int getDivu68kCycles_2 (uint32_t dividend, uint16_t divisor)
163 {
164 int mcycles;
165 uint32_t hdivisor;
166 int i;
167
168 if (divisor == 0)
169 return 0;
170
171 // Overflow
172 if ((dividend >> 16) >= divisor)
173 return (mcycles = 5) * 2;
174
175 mcycles = 38;
176 hdivisor = divisor << 16;
177
178 for(i=0; i<15; i++)
179 {
180 uint32_t temp;
181 temp = dividend;
182
183 dividend <<= 1;
184
185 // If carry from shift
186 if ((int32_t)temp < 0)
187 dividend -= hdivisor;
188 else
189 {
190 mcycles += 2;
191
192 if (dividend >= hdivisor)
193 {
194 dividend -= hdivisor;
195 mcycles--;
196 }
197 }
198 }
199
200 return mcycles * 2;
201 }
202
203
204 // This is called by cpuemu.c
getDivu68kCycles(uint32_t dividend,uint16_t divisor)205 int getDivu68kCycles(uint32_t dividend, uint16_t divisor)
206 {
207 int v = getDivu68kCycles_2(dividend, divisor) - 4;
208 // write_log ("U%d ", v);
209 return v;
210 }
211
212
213 //
214 // DIVS
215 // Signed division
216 //
getDivs68kCycles_2(int32_t dividend,int16_t divisor)217 static INLINE int getDivs68kCycles_2(int32_t dividend, int16_t divisor)
218 {
219 int mcycles;
220 uint32_t aquot;
221 int i;
222
223 if (divisor == 0)
224 return 0;
225
226 mcycles = 6;
227
228 if (dividend < 0)
229 mcycles++;
230
231 // Check for absolute overflow
232 if (((uint32_t)abs(dividend) >> 16) >= (uint16_t)abs(divisor))
233 return (mcycles + 2) * 2;
234
235 // Absolute quotient
236 aquot = (uint32_t)abs(dividend) / (uint16_t)abs(divisor);
237
238 mcycles += 55;
239
240 if (divisor >= 0)
241 {
242 if (dividend >= 0)
243 mcycles--;
244 else
245 mcycles++;
246 }
247
248 // Count 15 msbits in absolute of quotient
249
250 for(i=0; i<15; i++)
251 {
252 if ((int16_t)aquot >= 0)
253 mcycles++;
254
255 aquot <<= 1;
256 }
257
258 return mcycles * 2;
259 }
260
261
262 // This is called by cpuemu.c
getDivs68kCycles(int32_t dividend,int16_t divisor)263 int getDivs68kCycles(int32_t dividend, int16_t divisor)
264 {
265 int v = getDivs68kCycles_2(dividend, divisor) - 4;
266 // write_log ("S%d ", v);
267 return v;
268 }
269
270