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