Revision d7582078
b/target-i386/Makefile.objs | ||
---|---|---|
1 | 1 |
obj-y += translate.o op_helper.o helper.o cpu.o |
2 |
obj-y += excp_helper.o fpu_helper.o cc_helper.o |
|
2 |
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o
|
|
3 | 3 |
obj-$(CONFIG_SOFTMMU) += machine.o arch_memory_mapping.o arch_dump.o |
4 | 4 |
obj-$(CONFIG_KVM) += kvm.o hyperv.o |
5 | 5 |
obj-$(CONFIG_LINUX_USER) += ioport-user.o |
... | ... | |
8 | 8 |
$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) |
9 | 9 |
$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) |
10 | 10 |
$(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) |
11 |
$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) |
b/target-i386/int_helper.c | ||
---|---|---|
1 |
/* |
|
2 |
* x86 integer helpers |
|
3 |
* |
|
4 |
* Copyright (c) 2003 Fabrice Bellard |
|
5 |
* |
|
6 |
* This library is free software; you can redistribute it and/or |
|
7 |
* modify it under the terms of the GNU Lesser General Public |
|
8 |
* License as published by the Free Software Foundation; either |
|
9 |
* version 2 of the License, or (at your option) any later version. |
|
10 |
* |
|
11 |
* This library is distributed in the hope that it will be useful, |
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 |
* Lesser General Public License for more details. |
|
15 |
* |
|
16 |
* You should have received a copy of the GNU Lesser General Public |
|
17 |
* License along with this library; if not, see <http://www.gnu.org/licenses/>. |
|
18 |
*/ |
|
19 |
|
|
20 |
#include "cpu.h" |
|
21 |
#include "dyngen-exec.h" |
|
22 |
#include "host-utils.h" |
|
23 |
#include "helper.h" |
|
24 |
|
|
25 |
//#define DEBUG_MULDIV |
|
26 |
|
|
27 |
/* modulo 9 table */ |
|
28 |
static const uint8_t rclb_table[32] = { |
|
29 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
30 |
8, 0, 1, 2, 3, 4, 5, 6, |
|
31 |
7, 8, 0, 1, 2, 3, 4, 5, |
|
32 |
6, 7, 8, 0, 1, 2, 3, 4, |
|
33 |
}; |
|
34 |
|
|
35 |
/* modulo 17 table */ |
|
36 |
static const uint8_t rclw_table[32] = { |
|
37 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
38 |
8, 9, 10, 11, 12, 13, 14, 15, |
|
39 |
16, 0, 1, 2, 3, 4, 5, 6, |
|
40 |
7, 8, 9, 10, 11, 12, 13, 14, |
|
41 |
}; |
|
42 |
|
|
43 |
/* division, flags are undefined */ |
|
44 |
|
|
45 |
void helper_divb_AL(target_ulong t0) |
|
46 |
{ |
|
47 |
unsigned int num, den, q, r; |
|
48 |
|
|
49 |
num = (EAX & 0xffff); |
|
50 |
den = (t0 & 0xff); |
|
51 |
if (den == 0) { |
|
52 |
raise_exception(env, EXCP00_DIVZ); |
|
53 |
} |
|
54 |
q = (num / den); |
|
55 |
if (q > 0xff) { |
|
56 |
raise_exception(env, EXCP00_DIVZ); |
|
57 |
} |
|
58 |
q &= 0xff; |
|
59 |
r = (num % den) & 0xff; |
|
60 |
EAX = (EAX & ~0xffff) | (r << 8) | q; |
|
61 |
} |
|
62 |
|
|
63 |
void helper_idivb_AL(target_ulong t0) |
|
64 |
{ |
|
65 |
int num, den, q, r; |
|
66 |
|
|
67 |
num = (int16_t)EAX; |
|
68 |
den = (int8_t)t0; |
|
69 |
if (den == 0) { |
|
70 |
raise_exception(env, EXCP00_DIVZ); |
|
71 |
} |
|
72 |
q = (num / den); |
|
73 |
if (q != (int8_t)q) { |
|
74 |
raise_exception(env, EXCP00_DIVZ); |
|
75 |
} |
|
76 |
q &= 0xff; |
|
77 |
r = (num % den) & 0xff; |
|
78 |
EAX = (EAX & ~0xffff) | (r << 8) | q; |
|
79 |
} |
|
80 |
|
|
81 |
void helper_divw_AX(target_ulong t0) |
|
82 |
{ |
|
83 |
unsigned int num, den, q, r; |
|
84 |
|
|
85 |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
|
86 |
den = (t0 & 0xffff); |
|
87 |
if (den == 0) { |
|
88 |
raise_exception(env, EXCP00_DIVZ); |
|
89 |
} |
|
90 |
q = (num / den); |
|
91 |
if (q > 0xffff) { |
|
92 |
raise_exception(env, EXCP00_DIVZ); |
|
93 |
} |
|
94 |
q &= 0xffff; |
|
95 |
r = (num % den) & 0xffff; |
|
96 |
EAX = (EAX & ~0xffff) | q; |
|
97 |
EDX = (EDX & ~0xffff) | r; |
|
98 |
} |
|
99 |
|
|
100 |
void helper_idivw_AX(target_ulong t0) |
|
101 |
{ |
|
102 |
int num, den, q, r; |
|
103 |
|
|
104 |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
|
105 |
den = (int16_t)t0; |
|
106 |
if (den == 0) { |
|
107 |
raise_exception(env, EXCP00_DIVZ); |
|
108 |
} |
|
109 |
q = (num / den); |
|
110 |
if (q != (int16_t)q) { |
|
111 |
raise_exception(env, EXCP00_DIVZ); |
|
112 |
} |
|
113 |
q &= 0xffff; |
|
114 |
r = (num % den) & 0xffff; |
|
115 |
EAX = (EAX & ~0xffff) | q; |
|
116 |
EDX = (EDX & ~0xffff) | r; |
|
117 |
} |
|
118 |
|
|
119 |
void helper_divl_EAX(target_ulong t0) |
|
120 |
{ |
|
121 |
unsigned int den, r; |
|
122 |
uint64_t num, q; |
|
123 |
|
|
124 |
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); |
|
125 |
den = t0; |
|
126 |
if (den == 0) { |
|
127 |
raise_exception(env, EXCP00_DIVZ); |
|
128 |
} |
|
129 |
q = (num / den); |
|
130 |
r = (num % den); |
|
131 |
if (q > 0xffffffff) { |
|
132 |
raise_exception(env, EXCP00_DIVZ); |
|
133 |
} |
|
134 |
EAX = (uint32_t)q; |
|
135 |
EDX = (uint32_t)r; |
|
136 |
} |
|
137 |
|
|
138 |
void helper_idivl_EAX(target_ulong t0) |
|
139 |
{ |
|
140 |
int den, r; |
|
141 |
int64_t num, q; |
|
142 |
|
|
143 |
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); |
|
144 |
den = t0; |
|
145 |
if (den == 0) { |
|
146 |
raise_exception(env, EXCP00_DIVZ); |
|
147 |
} |
|
148 |
q = (num / den); |
|
149 |
r = (num % den); |
|
150 |
if (q != (int32_t)q) { |
|
151 |
raise_exception(env, EXCP00_DIVZ); |
|
152 |
} |
|
153 |
EAX = (uint32_t)q; |
|
154 |
EDX = (uint32_t)r; |
|
155 |
} |
|
156 |
|
|
157 |
/* bcd */ |
|
158 |
|
|
159 |
/* XXX: exception */ |
|
160 |
void helper_aam(int base) |
|
161 |
{ |
|
162 |
int al, ah; |
|
163 |
|
|
164 |
al = EAX & 0xff; |
|
165 |
ah = al / base; |
|
166 |
al = al % base; |
|
167 |
EAX = (EAX & ~0xffff) | al | (ah << 8); |
|
168 |
CC_DST = al; |
|
169 |
} |
|
170 |
|
|
171 |
void helper_aad(int base) |
|
172 |
{ |
|
173 |
int al, ah; |
|
174 |
|
|
175 |
al = EAX & 0xff; |
|
176 |
ah = (EAX >> 8) & 0xff; |
|
177 |
al = ((ah * base) + al) & 0xff; |
|
178 |
EAX = (EAX & ~0xffff) | al; |
|
179 |
CC_DST = al; |
|
180 |
} |
|
181 |
|
|
182 |
void helper_aaa(void) |
|
183 |
{ |
|
184 |
int icarry; |
|
185 |
int al, ah, af; |
|
186 |
int eflags; |
|
187 |
|
|
188 |
eflags = helper_cc_compute_all(CC_OP); |
|
189 |
af = eflags & CC_A; |
|
190 |
al = EAX & 0xff; |
|
191 |
ah = (EAX >> 8) & 0xff; |
|
192 |
|
|
193 |
icarry = (al > 0xf9); |
|
194 |
if (((al & 0x0f) > 9) || af) { |
|
195 |
al = (al + 6) & 0x0f; |
|
196 |
ah = (ah + 1 + icarry) & 0xff; |
|
197 |
eflags |= CC_C | CC_A; |
|
198 |
} else { |
|
199 |
eflags &= ~(CC_C | CC_A); |
|
200 |
al &= 0x0f; |
|
201 |
} |
|
202 |
EAX = (EAX & ~0xffff) | al | (ah << 8); |
|
203 |
CC_SRC = eflags; |
|
204 |
} |
|
205 |
|
|
206 |
void helper_aas(void) |
|
207 |
{ |
|
208 |
int icarry; |
|
209 |
int al, ah, af; |
|
210 |
int eflags; |
|
211 |
|
|
212 |
eflags = helper_cc_compute_all(CC_OP); |
|
213 |
af = eflags & CC_A; |
|
214 |
al = EAX & 0xff; |
|
215 |
ah = (EAX >> 8) & 0xff; |
|
216 |
|
|
217 |
icarry = (al < 6); |
|
218 |
if (((al & 0x0f) > 9) || af) { |
|
219 |
al = (al - 6) & 0x0f; |
|
220 |
ah = (ah - 1 - icarry) & 0xff; |
|
221 |
eflags |= CC_C | CC_A; |
|
222 |
} else { |
|
223 |
eflags &= ~(CC_C | CC_A); |
|
224 |
al &= 0x0f; |
|
225 |
} |
|
226 |
EAX = (EAX & ~0xffff) | al | (ah << 8); |
|
227 |
CC_SRC = eflags; |
|
228 |
} |
|
229 |
|
|
230 |
void helper_daa(void) |
|
231 |
{ |
|
232 |
int old_al, al, af, cf; |
|
233 |
int eflags; |
|
234 |
|
|
235 |
eflags = helper_cc_compute_all(CC_OP); |
|
236 |
cf = eflags & CC_C; |
|
237 |
af = eflags & CC_A; |
|
238 |
old_al = al = EAX & 0xff; |
|
239 |
|
|
240 |
eflags = 0; |
|
241 |
if (((al & 0x0f) > 9) || af) { |
|
242 |
al = (al + 6) & 0xff; |
|
243 |
eflags |= CC_A; |
|
244 |
} |
|
245 |
if ((old_al > 0x99) || cf) { |
|
246 |
al = (al + 0x60) & 0xff; |
|
247 |
eflags |= CC_C; |
|
248 |
} |
|
249 |
EAX = (EAX & ~0xff) | al; |
|
250 |
/* well, speed is not an issue here, so we compute the flags by hand */ |
|
251 |
eflags |= (al == 0) << 6; /* zf */ |
|
252 |
eflags |= parity_table[al]; /* pf */ |
|
253 |
eflags |= (al & 0x80); /* sf */ |
|
254 |
CC_SRC = eflags; |
|
255 |
} |
|
256 |
|
|
257 |
void helper_das(void) |
|
258 |
{ |
|
259 |
int al, al1, af, cf; |
|
260 |
int eflags; |
|
261 |
|
|
262 |
eflags = helper_cc_compute_all(CC_OP); |
|
263 |
cf = eflags & CC_C; |
|
264 |
af = eflags & CC_A; |
|
265 |
al = EAX & 0xff; |
|
266 |
|
|
267 |
eflags = 0; |
|
268 |
al1 = al; |
|
269 |
if (((al & 0x0f) > 9) || af) { |
|
270 |
eflags |= CC_A; |
|
271 |
if (al < 6 || cf) { |
|
272 |
eflags |= CC_C; |
|
273 |
} |
|
274 |
al = (al - 6) & 0xff; |
|
275 |
} |
|
276 |
if ((al1 > 0x99) || cf) { |
|
277 |
al = (al - 0x60) & 0xff; |
|
278 |
eflags |= CC_C; |
|
279 |
} |
|
280 |
EAX = (EAX & ~0xff) | al; |
|
281 |
/* well, speed is not an issue here, so we compute the flags by hand */ |
|
282 |
eflags |= (al == 0) << 6; /* zf */ |
|
283 |
eflags |= parity_table[al]; /* pf */ |
|
284 |
eflags |= (al & 0x80); /* sf */ |
|
285 |
CC_SRC = eflags; |
|
286 |
} |
|
287 |
|
|
288 |
#ifdef TARGET_X86_64 |
|
289 |
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) |
|
290 |
{ |
|
291 |
*plow += a; |
|
292 |
/* carry test */ |
|
293 |
if (*plow < a) { |
|
294 |
(*phigh)++; |
|
295 |
} |
|
296 |
*phigh += b; |
|
297 |
} |
|
298 |
|
|
299 |
static void neg128(uint64_t *plow, uint64_t *phigh) |
|
300 |
{ |
|
301 |
*plow = ~*plow; |
|
302 |
*phigh = ~*phigh; |
|
303 |
add128(plow, phigh, 1, 0); |
|
304 |
} |
|
305 |
|
|
306 |
/* return TRUE if overflow */ |
|
307 |
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) |
|
308 |
{ |
|
309 |
uint64_t q, r, a1, a0; |
|
310 |
int i, qb, ab; |
|
311 |
|
|
312 |
a0 = *plow; |
|
313 |
a1 = *phigh; |
|
314 |
if (a1 == 0) { |
|
315 |
q = a0 / b; |
|
316 |
r = a0 % b; |
|
317 |
*plow = q; |
|
318 |
*phigh = r; |
|
319 |
} else { |
|
320 |
if (a1 >= b) { |
|
321 |
return 1; |
|
322 |
} |
|
323 |
/* XXX: use a better algorithm */ |
|
324 |
for (i = 0; i < 64; i++) { |
|
325 |
ab = a1 >> 63; |
|
326 |
a1 = (a1 << 1) | (a0 >> 63); |
|
327 |
if (ab || a1 >= b) { |
|
328 |
a1 -= b; |
|
329 |
qb = 1; |
|
330 |
} else { |
|
331 |
qb = 0; |
|
332 |
} |
|
333 |
a0 = (a0 << 1) | qb; |
|
334 |
} |
|
335 |
#if defined(DEBUG_MULDIV) |
|
336 |
printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 |
|
337 |
": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", |
|
338 |
*phigh, *plow, b, a0, a1); |
|
339 |
#endif |
|
340 |
*plow = a0; |
|
341 |
*phigh = a1; |
|
342 |
} |
|
343 |
return 0; |
|
344 |
} |
|
345 |
|
|
346 |
/* return TRUE if overflow */ |
|
347 |
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) |
|
348 |
{ |
|
349 |
int sa, sb; |
|
350 |
|
|
351 |
sa = ((int64_t)*phigh < 0); |
|
352 |
if (sa) { |
|
353 |
neg128(plow, phigh); |
|
354 |
} |
|
355 |
sb = (b < 0); |
|
356 |
if (sb) { |
|
357 |
b = -b; |
|
358 |
} |
|
359 |
if (div64(plow, phigh, b) != 0) { |
|
360 |
return 1; |
|
361 |
} |
|
362 |
if (sa ^ sb) { |
|
363 |
if (*plow > (1ULL << 63)) { |
|
364 |
return 1; |
|
365 |
} |
|
366 |
*plow = -*plow; |
|
367 |
} else { |
|
368 |
if (*plow >= (1ULL << 63)) { |
|
369 |
return 1; |
|
370 |
} |
|
371 |
} |
|
372 |
if (sa) { |
|
373 |
*phigh = -*phigh; |
|
374 |
} |
|
375 |
return 0; |
|
376 |
} |
|
377 |
|
|
378 |
void helper_mulq_EAX_T0(target_ulong t0) |
|
379 |
{ |
|
380 |
uint64_t r0, r1; |
|
381 |
|
|
382 |
mulu64(&r0, &r1, EAX, t0); |
|
383 |
EAX = r0; |
|
384 |
EDX = r1; |
|
385 |
CC_DST = r0; |
|
386 |
CC_SRC = r1; |
|
387 |
} |
|
388 |
|
|
389 |
void helper_imulq_EAX_T0(target_ulong t0) |
|
390 |
{ |
|
391 |
uint64_t r0, r1; |
|
392 |
|
|
393 |
muls64(&r0, &r1, EAX, t0); |
|
394 |
EAX = r0; |
|
395 |
EDX = r1; |
|
396 |
CC_DST = r0; |
|
397 |
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); |
|
398 |
} |
|
399 |
|
|
400 |
target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1) |
|
401 |
{ |
|
402 |
uint64_t r0, r1; |
|
403 |
|
|
404 |
muls64(&r0, &r1, t0, t1); |
|
405 |
CC_DST = r0; |
|
406 |
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); |
|
407 |
return r0; |
|
408 |
} |
|
409 |
|
|
410 |
void helper_divq_EAX(target_ulong t0) |
|
411 |
{ |
|
412 |
uint64_t r0, r1; |
|
413 |
|
|
414 |
if (t0 == 0) { |
|
415 |
raise_exception(env, EXCP00_DIVZ); |
|
416 |
} |
|
417 |
r0 = EAX; |
|
418 |
r1 = EDX; |
|
419 |
if (div64(&r0, &r1, t0)) { |
|
420 |
raise_exception(env, EXCP00_DIVZ); |
|
421 |
} |
|
422 |
EAX = r0; |
|
423 |
EDX = r1; |
|
424 |
} |
|
425 |
|
|
426 |
void helper_idivq_EAX(target_ulong t0) |
|
427 |
{ |
|
428 |
uint64_t r0, r1; |
|
429 |
|
|
430 |
if (t0 == 0) { |
|
431 |
raise_exception(env, EXCP00_DIVZ); |
|
432 |
} |
|
433 |
r0 = EAX; |
|
434 |
r1 = EDX; |
|
435 |
if (idiv64(&r0, &r1, t0)) { |
|
436 |
raise_exception(env, EXCP00_DIVZ); |
|
437 |
} |
|
438 |
EAX = r0; |
|
439 |
EDX = r1; |
|
440 |
} |
|
441 |
#endif |
|
442 |
|
|
443 |
/* bit operations */ |
|
444 |
target_ulong helper_bsf(target_ulong t0) |
|
445 |
{ |
|
446 |
int count; |
|
447 |
target_ulong res; |
|
448 |
|
|
449 |
res = t0; |
|
450 |
count = 0; |
|
451 |
while ((res & 1) == 0) { |
|
452 |
count++; |
|
453 |
res >>= 1; |
|
454 |
} |
|
455 |
return count; |
|
456 |
} |
|
457 |
|
|
458 |
target_ulong helper_lzcnt(target_ulong t0, int wordsize) |
|
459 |
{ |
|
460 |
int count; |
|
461 |
target_ulong res, mask; |
|
462 |
|
|
463 |
if (wordsize > 0 && t0 == 0) { |
|
464 |
return wordsize; |
|
465 |
} |
|
466 |
res = t0; |
|
467 |
count = TARGET_LONG_BITS - 1; |
|
468 |
mask = (target_ulong)1 << (TARGET_LONG_BITS - 1); |
|
469 |
while ((res & mask) == 0) { |
|
470 |
count--; |
|
471 |
res <<= 1; |
|
472 |
} |
|
473 |
if (wordsize > 0) { |
|
474 |
return wordsize - 1 - count; |
|
475 |
} |
|
476 |
return count; |
|
477 |
} |
|
478 |
|
|
479 |
target_ulong helper_bsr(target_ulong t0) |
|
480 |
{ |
|
481 |
return helper_lzcnt(t0, 0); |
|
482 |
} |
|
483 |
|
|
484 |
#define SHIFT 0 |
|
485 |
#include "shift_helper_template.h" |
|
486 |
#undef SHIFT |
|
487 |
|
|
488 |
#define SHIFT 1 |
|
489 |
#include "shift_helper_template.h" |
|
490 |
#undef SHIFT |
|
491 |
|
|
492 |
#define SHIFT 2 |
|
493 |
#include "shift_helper_template.h" |
|
494 |
#undef SHIFT |
|
495 |
|
|
496 |
#ifdef TARGET_X86_64 |
|
497 |
#define SHIFT 3 |
|
498 |
#include "shift_helper_template.h" |
|
499 |
#undef SHIFT |
|
500 |
#endif |
b/target-i386/op_helper.c | ||
---|---|---|
19 | 19 |
|
20 | 20 |
#include "cpu.h" |
21 | 21 |
#include "dyngen-exec.h" |
22 |
#include "host-utils.h" |
|
23 | 22 |
#include "ioport.h" |
24 | 23 |
#include "qemu-log.h" |
25 | 24 |
#include "cpu-defs.h" |
... | ... | |
30 | 29 |
#endif /* !defined(CONFIG_USER_ONLY) */ |
31 | 30 |
|
32 | 31 |
//#define DEBUG_PCALL |
33 |
//#define DEBUG_MULDIV |
|
34 | 32 |
|
35 | 33 |
#ifdef DEBUG_PCALL |
36 | 34 |
# define LOG_PCALL(...) qemu_log_mask(CPU_LOG_PCALL, ## __VA_ARGS__) |
... | ... | |
41 | 39 |
# define LOG_PCALL_STATE(env) do { } while (0) |
42 | 40 |
#endif |
43 | 41 |
|
44 |
/* modulo 17 table */ |
|
45 |
static const uint8_t rclw_table[32] = { |
|
46 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
47 |
8, 9, 10, 11, 12, 13, 14, 15, |
|
48 |
16, 0, 1, 2, 3, 4, 5, 6, |
|
49 |
7, 8, 9, 10, 11, 12, 13, 14, |
|
50 |
}; |
|
51 |
|
|
52 |
/* modulo 9 table */ |
|
53 |
static const uint8_t rclb_table[32] = { |
|
54 |
0, 1, 2, 3, 4, 5, 6, 7, |
|
55 |
8, 0, 1, 2, 3, 4, 5, 6, |
|
56 |
7, 8, 0, 1, 2, 3, 4, 5, |
|
57 |
6, 7, 8, 0, 1, 2, 3, 4, |
|
58 |
}; |
|
59 |
|
|
60 | 42 |
/* broken thread support */ |
61 | 43 |
|
62 | 44 |
static spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; |
... | ... | |
1656 | 1638 |
|
1657 | 1639 |
#endif /* !CONFIG_USER_ONLY */ |
1658 | 1640 |
|
1659 |
|
|
1660 |
/* division, flags are undefined */ |
|
1661 |
|
|
1662 |
void helper_divb_AL(target_ulong t0) |
|
1663 |
{ |
|
1664 |
unsigned int num, den, q, r; |
|
1665 |
|
|
1666 |
num = (EAX & 0xffff); |
|
1667 |
den = (t0 & 0xff); |
|
1668 |
if (den == 0) { |
|
1669 |
raise_exception(env, EXCP00_DIVZ); |
|
1670 |
} |
|
1671 |
q = (num / den); |
|
1672 |
if (q > 0xff) { |
|
1673 |
raise_exception(env, EXCP00_DIVZ); |
|
1674 |
} |
|
1675 |
q &= 0xff; |
|
1676 |
r = (num % den) & 0xff; |
|
1677 |
EAX = (EAX & ~0xffff) | (r << 8) | q; |
|
1678 |
} |
|
1679 |
|
|
1680 |
void helper_idivb_AL(target_ulong t0) |
|
1681 |
{ |
|
1682 |
int num, den, q, r; |
|
1683 |
|
|
1684 |
num = (int16_t)EAX; |
|
1685 |
den = (int8_t)t0; |
|
1686 |
if (den == 0) { |
|
1687 |
raise_exception(env, EXCP00_DIVZ); |
|
1688 |
} |
|
1689 |
q = (num / den); |
|
1690 |
if (q != (int8_t)q) { |
|
1691 |
raise_exception(env, EXCP00_DIVZ); |
|
1692 |
} |
|
1693 |
q &= 0xff; |
|
1694 |
r = (num % den) & 0xff; |
|
1695 |
EAX = (EAX & ~0xffff) | (r << 8) | q; |
|
1696 |
} |
|
1697 |
|
|
1698 |
void helper_divw_AX(target_ulong t0) |
|
1699 |
{ |
|
1700 |
unsigned int num, den, q, r; |
|
1701 |
|
|
1702 |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
|
1703 |
den = (t0 & 0xffff); |
|
1704 |
if (den == 0) { |
|
1705 |
raise_exception(env, EXCP00_DIVZ); |
|
1706 |
} |
|
1707 |
q = (num / den); |
|
1708 |
if (q > 0xffff) { |
|
1709 |
raise_exception(env, EXCP00_DIVZ); |
|
1710 |
} |
|
1711 |
q &= 0xffff; |
|
1712 |
r = (num % den) & 0xffff; |
|
1713 |
EAX = (EAX & ~0xffff) | q; |
|
1714 |
EDX = (EDX & ~0xffff) | r; |
|
1715 |
} |
|
1716 |
|
|
1717 |
void helper_idivw_AX(target_ulong t0) |
|
1718 |
{ |
|
1719 |
int num, den, q, r; |
|
1720 |
|
|
1721 |
num = (EAX & 0xffff) | ((EDX & 0xffff) << 16); |
|
1722 |
den = (int16_t)t0; |
|
1723 |
if (den == 0) { |
|
1724 |
raise_exception(env, EXCP00_DIVZ); |
|
1725 |
} |
|
1726 |
q = (num / den); |
|
1727 |
if (q != (int16_t)q) { |
|
1728 |
raise_exception(env, EXCP00_DIVZ); |
|
1729 |
} |
|
1730 |
q &= 0xffff; |
|
1731 |
r = (num % den) & 0xffff; |
|
1732 |
EAX = (EAX & ~0xffff) | q; |
|
1733 |
EDX = (EDX & ~0xffff) | r; |
|
1734 |
} |
|
1735 |
|
|
1736 |
void helper_divl_EAX(target_ulong t0) |
|
1737 |
{ |
|
1738 |
unsigned int den, r; |
|
1739 |
uint64_t num, q; |
|
1740 |
|
|
1741 |
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); |
|
1742 |
den = t0; |
|
1743 |
if (den == 0) { |
|
1744 |
raise_exception(env, EXCP00_DIVZ); |
|
1745 |
} |
|
1746 |
q = (num / den); |
|
1747 |
r = (num % den); |
|
1748 |
if (q > 0xffffffff) { |
|
1749 |
raise_exception(env, EXCP00_DIVZ); |
|
1750 |
} |
|
1751 |
EAX = (uint32_t)q; |
|
1752 |
EDX = (uint32_t)r; |
|
1753 |
} |
|
1754 |
|
|
1755 |
void helper_idivl_EAX(target_ulong t0) |
|
1756 |
{ |
|
1757 |
int den, r; |
|
1758 |
int64_t num, q; |
|
1759 |
|
|
1760 |
num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32); |
|
1761 |
den = t0; |
|
1762 |
if (den == 0) { |
|
1763 |
raise_exception(env, EXCP00_DIVZ); |
|
1764 |
} |
|
1765 |
q = (num / den); |
|
1766 |
r = (num % den); |
|
1767 |
if (q != (int32_t)q) { |
|
1768 |
raise_exception(env, EXCP00_DIVZ); |
|
1769 |
} |
|
1770 |
EAX = (uint32_t)q; |
|
1771 |
EDX = (uint32_t)r; |
|
1772 |
} |
|
1773 |
|
|
1774 |
/* bcd */ |
|
1775 |
|
|
1776 |
/* XXX: exception */ |
|
1777 |
void helper_aam(int base) |
|
1778 |
{ |
|
1779 |
int al, ah; |
|
1780 |
|
|
1781 |
al = EAX & 0xff; |
|
1782 |
ah = al / base; |
|
1783 |
al = al % base; |
|
1784 |
EAX = (EAX & ~0xffff) | al | (ah << 8); |
|
1785 |
CC_DST = al; |
|
1786 |
} |
|
1787 |
|
|
1788 |
void helper_aad(int base) |
|
1789 |
{ |
|
1790 |
int al, ah; |
|
1791 |
|
|
1792 |
al = EAX & 0xff; |
|
1793 |
ah = (EAX >> 8) & 0xff; |
|
1794 |
al = ((ah * base) + al) & 0xff; |
|
1795 |
EAX = (EAX & ~0xffff) | al; |
|
1796 |
CC_DST = al; |
|
1797 |
} |
|
1798 |
|
|
1799 |
void helper_aaa(void) |
|
1800 |
{ |
|
1801 |
int icarry; |
|
1802 |
int al, ah, af; |
|
1803 |
int eflags; |
|
1804 |
|
|
1805 |
eflags = helper_cc_compute_all(CC_OP); |
|
1806 |
af = eflags & CC_A; |
|
1807 |
al = EAX & 0xff; |
|
1808 |
ah = (EAX >> 8) & 0xff; |
|
1809 |
|
|
1810 |
icarry = (al > 0xf9); |
|
1811 |
if (((al & 0x0f) > 9) || af) { |
|
1812 |
al = (al + 6) & 0x0f; |
|
1813 |
ah = (ah + 1 + icarry) & 0xff; |
|
1814 |
eflags |= CC_C | CC_A; |
|
1815 |
} else { |
|
1816 |
eflags &= ~(CC_C | CC_A); |
|
1817 |
al &= 0x0f; |
|
1818 |
} |
|
1819 |
EAX = (EAX & ~0xffff) | al | (ah << 8); |
|
1820 |
CC_SRC = eflags; |
|
1821 |
} |
|
1822 |
|
|
1823 |
void helper_aas(void) |
|
1824 |
{ |
|
1825 |
int icarry; |
|
1826 |
int al, ah, af; |
|
1827 |
int eflags; |
|
1828 |
|
|
1829 |
eflags = helper_cc_compute_all(CC_OP); |
|
1830 |
af = eflags & CC_A; |
|
1831 |
al = EAX & 0xff; |
|
1832 |
ah = (EAX >> 8) & 0xff; |
|
1833 |
|
|
1834 |
icarry = (al < 6); |
|
1835 |
if (((al & 0x0f) > 9) || af) { |
|
1836 |
al = (al - 6) & 0x0f; |
|
1837 |
ah = (ah - 1 - icarry) & 0xff; |
|
1838 |
eflags |= CC_C | CC_A; |
|
1839 |
} else { |
|
1840 |
eflags &= ~(CC_C | CC_A); |
|
1841 |
al &= 0x0f; |
|
1842 |
} |
|
1843 |
EAX = (EAX & ~0xffff) | al | (ah << 8); |
|
1844 |
CC_SRC = eflags; |
|
1845 |
} |
|
1846 |
|
|
1847 |
void helper_daa(void) |
|
1848 |
{ |
|
1849 |
int old_al, al, af, cf; |
|
1850 |
int eflags; |
|
1851 |
|
|
1852 |
eflags = helper_cc_compute_all(CC_OP); |
|
1853 |
cf = eflags & CC_C; |
|
1854 |
af = eflags & CC_A; |
|
1855 |
old_al = al = EAX & 0xff; |
|
1856 |
|
|
1857 |
eflags = 0; |
|
1858 |
if (((al & 0x0f) > 9) || af) { |
|
1859 |
al = (al + 6) & 0xff; |
|
1860 |
eflags |= CC_A; |
|
1861 |
} |
|
1862 |
if ((old_al > 0x99) || cf) { |
|
1863 |
al = (al + 0x60) & 0xff; |
|
1864 |
eflags |= CC_C; |
|
1865 |
} |
|
1866 |
EAX = (EAX & ~0xff) | al; |
|
1867 |
/* well, speed is not an issue here, so we compute the flags by hand */ |
|
1868 |
eflags |= (al == 0) << 6; /* zf */ |
|
1869 |
eflags |= parity_table[al]; /* pf */ |
|
1870 |
eflags |= (al & 0x80); /* sf */ |
|
1871 |
CC_SRC = eflags; |
|
1872 |
} |
|
1873 |
|
|
1874 |
void helper_das(void) |
|
1875 |
{ |
|
1876 |
int al, al1, af, cf; |
|
1877 |
int eflags; |
|
1878 |
|
|
1879 |
eflags = helper_cc_compute_all(CC_OP); |
|
1880 |
cf = eflags & CC_C; |
|
1881 |
af = eflags & CC_A; |
|
1882 |
al = EAX & 0xff; |
|
1883 |
|
|
1884 |
eflags = 0; |
|
1885 |
al1 = al; |
|
1886 |
if (((al & 0x0f) > 9) || af) { |
|
1887 |
eflags |= CC_A; |
|
1888 |
if (al < 6 || cf) { |
|
1889 |
eflags |= CC_C; |
|
1890 |
} |
|
1891 |
al = (al - 6) & 0xff; |
|
1892 |
} |
|
1893 |
if ((al1 > 0x99) || cf) { |
|
1894 |
al = (al - 0x60) & 0xff; |
|
1895 |
eflags |= CC_C; |
|
1896 |
} |
|
1897 |
EAX = (EAX & ~0xff) | al; |
|
1898 |
/* well, speed is not an issue here, so we compute the flags by hand */ |
|
1899 |
eflags |= (al == 0) << 6; /* zf */ |
|
1900 |
eflags |= parity_table[al]; /* pf */ |
|
1901 |
eflags |= (al & 0x80); /* sf */ |
|
1902 |
CC_SRC = eflags; |
|
1903 |
} |
|
1904 |
|
|
1905 | 1641 |
void helper_into(int next_eip_addend) |
1906 | 1642 |
{ |
1907 | 1643 |
int eflags; |
... | ... | |
3614 | 3350 |
} |
3615 | 3351 |
#endif |
3616 | 3352 |
|
3617 |
#ifdef TARGET_X86_64 |
|
3618 |
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b) |
|
3619 |
{ |
|
3620 |
*plow += a; |
|
3621 |
/* carry test */ |
|
3622 |
if (*plow < a) { |
|
3623 |
(*phigh)++; |
|
3624 |
} |
|
3625 |
*phigh += b; |
|
3626 |
} |
|
3627 |
|
|
3628 |
static void neg128(uint64_t *plow, uint64_t *phigh) |
|
3629 |
{ |
|
3630 |
*plow = ~*plow; |
|
3631 |
*phigh = ~*phigh; |
|
3632 |
add128(plow, phigh, 1, 0); |
|
3633 |
} |
|
3634 |
|
|
3635 |
/* return TRUE if overflow */ |
|
3636 |
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b) |
|
3637 |
{ |
|
3638 |
uint64_t q, r, a1, a0; |
|
3639 |
int i, qb, ab; |
|
3640 |
|
|
3641 |
a0 = *plow; |
|
3642 |
a1 = *phigh; |
|
3643 |
if (a1 == 0) { |
|
3644 |
q = a0 / b; |
|
3645 |
r = a0 % b; |
|
3646 |
*plow = q; |
|
3647 |
*phigh = r; |
|
3648 |
} else { |
|
3649 |
if (a1 >= b) { |
|
3650 |
return 1; |
|
3651 |
} |
|
3652 |
/* XXX: use a better algorithm */ |
|
3653 |
for (i = 0; i < 64; i++) { |
|
3654 |
ab = a1 >> 63; |
|
3655 |
a1 = (a1 << 1) | (a0 >> 63); |
|
3656 |
if (ab || a1 >= b) { |
|
3657 |
a1 -= b; |
|
3658 |
qb = 1; |
|
3659 |
} else { |
|
3660 |
qb = 0; |
|
3661 |
} |
|
3662 |
a0 = (a0 << 1) | qb; |
|
3663 |
} |
|
3664 |
#if defined(DEBUG_MULDIV) |
|
3665 |
printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 |
|
3666 |
": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n", |
|
3667 |
*phigh, *plow, b, a0, a1); |
|
3668 |
#endif |
|
3669 |
*plow = a0; |
|
3670 |
*phigh = a1; |
|
3671 |
} |
|
3672 |
return 0; |
|
3673 |
} |
|
3674 |
|
|
3675 |
/* return TRUE if overflow */ |
|
3676 |
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b) |
|
3677 |
{ |
|
3678 |
int sa, sb; |
|
3679 |
|
|
3680 |
sa = ((int64_t)*phigh < 0); |
|
3681 |
if (sa) { |
|
3682 |
neg128(plow, phigh); |
|
3683 |
} |
|
3684 |
sb = (b < 0); |
|
3685 |
if (sb) { |
|
3686 |
b = -b; |
|
3687 |
} |
|
3688 |
if (div64(plow, phigh, b) != 0) { |
|
3689 |
return 1; |
|
3690 |
} |
|
3691 |
if (sa ^ sb) { |
|
3692 |
if (*plow > (1ULL << 63)) { |
|
3693 |
return 1; |
|
3694 |
} |
|
3695 |
*plow = -*plow; |
|
3696 |
} else { |
|
3697 |
if (*plow >= (1ULL << 63)) { |
|
3698 |
return 1; |
|
3699 |
} |
|
3700 |
} |
|
3701 |
if (sa) { |
|
3702 |
*phigh = -*phigh; |
|
3703 |
} |
|
3704 |
return 0; |
|
3705 |
} |
|
3706 |
|
|
3707 |
void helper_mulq_EAX_T0(target_ulong t0) |
|
3708 |
{ |
|
3709 |
uint64_t r0, r1; |
|
3710 |
|
|
3711 |
mulu64(&r0, &r1, EAX, t0); |
|
3712 |
EAX = r0; |
|
3713 |
EDX = r1; |
|
3714 |
CC_DST = r0; |
|
3715 |
CC_SRC = r1; |
|
3716 |
} |
|
3717 |
|
|
3718 |
void helper_imulq_EAX_T0(target_ulong t0) |
|
3719 |
{ |
|
3720 |
uint64_t r0, r1; |
|
3721 |
|
|
3722 |
muls64(&r0, &r1, EAX, t0); |
|
3723 |
EAX = r0; |
|
3724 |
EDX = r1; |
|
3725 |
CC_DST = r0; |
|
3726 |
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); |
|
3727 |
} |
|
3728 |
|
|
3729 |
target_ulong helper_imulq_T0_T1(target_ulong t0, target_ulong t1) |
|
3730 |
{ |
|
3731 |
uint64_t r0, r1; |
|
3732 |
|
|
3733 |
muls64(&r0, &r1, t0, t1); |
|
3734 |
CC_DST = r0; |
|
3735 |
CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63)); |
|
3736 |
return r0; |
|
3737 |
} |
|
3738 |
|
|
3739 |
void helper_divq_EAX(target_ulong t0) |
|
3740 |
{ |
|
3741 |
uint64_t r0, r1; |
|
3742 |
|
|
3743 |
if (t0 == 0) { |
|
3744 |
raise_exception(env, EXCP00_DIVZ); |
|
3745 |
} |
|
3746 |
r0 = EAX; |
|
3747 |
r1 = EDX; |
|
3748 |
if (div64(&r0, &r1, t0)) { |
|
3749 |
raise_exception(env, EXCP00_DIVZ); |
|
3750 |
} |
|
3751 |
EAX = r0; |
|
3752 |
EDX = r1; |
|
3753 |
} |
|
3754 |
|
|
3755 |
void helper_idivq_EAX(target_ulong t0) |
|
3756 |
{ |
|
3757 |
uint64_t r0, r1; |
|
3758 |
|
|
3759 |
if (t0 == 0) { |
|
3760 |
raise_exception(env, EXCP00_DIVZ); |
|
3761 |
} |
|
3762 |
r0 = EAX; |
|
3763 |
r1 = EDX; |
|
3764 |
if (idiv64(&r0, &r1, t0)) { |
|
3765 |
raise_exception(env, EXCP00_DIVZ); |
|
3766 |
} |
|
3767 |
EAX = r0; |
|
3768 |
EDX = r1; |
|
3769 |
} |
|
3770 |
#endif |
|
3771 |
|
|
3772 | 3353 |
static void do_hlt(void) |
3773 | 3354 |
{ |
3774 | 3355 |
env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */ |
... | ... | |
4583 | 4164 |
} |
4584 | 4165 |
|
4585 | 4166 |
#endif |
4586 |
|
|
4587 |
#define SHIFT 0 |
|
4588 |
#include "shift_helper_template.h" |
|
4589 |
#undef SHIFT |
|
4590 |
|
|
4591 |
#define SHIFT 1 |
|
4592 |
#include "shift_helper_template.h" |
|
4593 |
#undef SHIFT |
|
4594 |
|
|
4595 |
#define SHIFT 2 |
|
4596 |
#include "shift_helper_template.h" |
|
4597 |
#undef SHIFT |
|
4598 |
|
|
4599 |
#ifdef TARGET_X86_64 |
|
4600 |
#define SHIFT 3 |
|
4601 |
#include "shift_helper_template.h" |
|
4602 |
#undef SHIFT |
|
4603 |
#endif |
|
4604 |
|
|
4605 |
/* bit operations */ |
|
4606 |
target_ulong helper_bsf(target_ulong t0) |
|
4607 |
{ |
|
4608 |
int count; |
|
4609 |
target_ulong res; |
|
4610 |
|
|
4611 |
res = t0; |
|
4612 |
count = 0; |
|
4613 |
while ((res & 1) == 0) { |
|
4614 |
count++; |
|
4615 |
res >>= 1; |
|
4616 |
} |
|
4617 |
return count; |
|
4618 |
} |
|
4619 |
|
|
4620 |
target_ulong helper_lzcnt(target_ulong t0, int wordsize) |
|
4621 |
{ |
|
4622 |
int count; |
|
4623 |
target_ulong res, mask; |
|
4624 |
|
|
4625 |
if (wordsize > 0 && t0 == 0) { |
|
4626 |
return wordsize; |
|
4627 |
} |
|
4628 |
res = t0; |
|
4629 |
count = TARGET_LONG_BITS - 1; |
|
4630 |
mask = (target_ulong)1 << (TARGET_LONG_BITS - 1); |
|
4631 |
while ((res & mask) == 0) { |
|
4632 |
count--; |
|
4633 |
res <<= 1; |
|
4634 |
} |
|
4635 |
if (wordsize > 0) { |
|
4636 |
return wordsize - 1 - count; |
|
4637 |
} |
|
4638 |
return count; |
|
4639 |
} |
|
4640 |
|
|
4641 |
target_ulong helper_bsr(target_ulong t0) |
|
4642 |
{ |
|
4643 |
return helper_lzcnt(t0, 0); |
|
4644 |
} |
Also available in: Unified diff