tests/acceptance: verify s390x device detection
[qemu/ar7.git] / target / i386 / int_helper.c
blob4f89436b53f7468edb7e602c00236d210c4ffd7a
1 /*
2 * x86 integer helpers
4 * Copyright (c) 2003 Fabrice Bellard
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.1 of the License, or (at your option) any later version.
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.
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/>.
20 #include "qemu/osdep.h"
21 #include "cpu.h"
22 #include "exec/exec-all.h"
23 #include "qemu/host-utils.h"
24 #include "exec/helper-proto.h"
25 #include "qapi/error.h"
26 #include "qemu/guest-random.h"
28 //#define DEBUG_MULDIV
30 /* modulo 9 table */
31 static const uint8_t rclb_table[32] = {
32 0, 1, 2, 3, 4, 5, 6, 7,
33 8, 0, 1, 2, 3, 4, 5, 6,
34 7, 8, 0, 1, 2, 3, 4, 5,
35 6, 7, 8, 0, 1, 2, 3, 4,
38 /* modulo 17 table */
39 static const uint8_t rclw_table[32] = {
40 0, 1, 2, 3, 4, 5, 6, 7,
41 8, 9, 10, 11, 12, 13, 14, 15,
42 16, 0, 1, 2, 3, 4, 5, 6,
43 7, 8, 9, 10, 11, 12, 13, 14,
46 /* division, flags are undefined */
48 void helper_divb_AL(CPUX86State *env, target_ulong t0)
50 unsigned int num, den, q, r;
52 num = (env->regs[R_EAX] & 0xffff);
53 den = (t0 & 0xff);
54 if (den == 0) {
55 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
57 q = (num / den);
58 if (q > 0xff) {
59 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
61 q &= 0xff;
62 r = (num % den) & 0xff;
63 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q;
66 void helper_idivb_AL(CPUX86State *env, target_ulong t0)
68 int num, den, q, r;
70 num = (int16_t)env->regs[R_EAX];
71 den = (int8_t)t0;
72 if (den == 0) {
73 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
75 q = (num / den);
76 if (q != (int8_t)q) {
77 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
79 q &= 0xff;
80 r = (num % den) & 0xff;
81 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q;
84 void helper_divw_AX(CPUX86State *env, target_ulong t0)
86 unsigned int num, den, q, r;
88 num = (env->regs[R_EAX] & 0xffff) | ((env->regs[R_EDX] & 0xffff) << 16);
89 den = (t0 & 0xffff);
90 if (den == 0) {
91 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
93 q = (num / den);
94 if (q > 0xffff) {
95 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
97 q &= 0xffff;
98 r = (num % den) & 0xffff;
99 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | q;
100 env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r;
103 void helper_idivw_AX(CPUX86State *env, target_ulong t0)
105 int num, den, q, r;
107 num = (env->regs[R_EAX] & 0xffff) | ((env->regs[R_EDX] & 0xffff) << 16);
108 den = (int16_t)t0;
109 if (den == 0) {
110 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
112 q = (num / den);
113 if (q != (int16_t)q) {
114 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
116 q &= 0xffff;
117 r = (num % den) & 0xffff;
118 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | q;
119 env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r;
122 void helper_divl_EAX(CPUX86State *env, target_ulong t0)
124 unsigned int den, r;
125 uint64_t num, q;
127 num = ((uint32_t)env->regs[R_EAX]) | ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
128 den = t0;
129 if (den == 0) {
130 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
132 q = (num / den);
133 r = (num % den);
134 if (q > 0xffffffff) {
135 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
137 env->regs[R_EAX] = (uint32_t)q;
138 env->regs[R_EDX] = (uint32_t)r;
141 void helper_idivl_EAX(CPUX86State *env, target_ulong t0)
143 int den, r;
144 int64_t num, q;
146 num = ((uint32_t)env->regs[R_EAX]) | ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
147 den = t0;
148 if (den == 0) {
149 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
151 q = (num / den);
152 r = (num % den);
153 if (q != (int32_t)q) {
154 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
156 env->regs[R_EAX] = (uint32_t)q;
157 env->regs[R_EDX] = (uint32_t)r;
160 /* bcd */
162 /* XXX: exception */
163 void helper_aam(CPUX86State *env, int base)
165 int al, ah;
167 al = env->regs[R_EAX] & 0xff;
168 ah = al / base;
169 al = al % base;
170 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
171 CC_DST = al;
174 void helper_aad(CPUX86State *env, int base)
176 int al, ah;
178 al = env->regs[R_EAX] & 0xff;
179 ah = (env->regs[R_EAX] >> 8) & 0xff;
180 al = ((ah * base) + al) & 0xff;
181 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al;
182 CC_DST = al;
185 void helper_aaa(CPUX86State *env)
187 int icarry;
188 int al, ah, af;
189 int eflags;
191 eflags = cpu_cc_compute_all(env, CC_OP);
192 af = eflags & CC_A;
193 al = env->regs[R_EAX] & 0xff;
194 ah = (env->regs[R_EAX] >> 8) & 0xff;
196 icarry = (al > 0xf9);
197 if (((al & 0x0f) > 9) || af) {
198 al = (al + 6) & 0x0f;
199 ah = (ah + 1 + icarry) & 0xff;
200 eflags |= CC_C | CC_A;
201 } else {
202 eflags &= ~(CC_C | CC_A);
203 al &= 0x0f;
205 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
206 CC_SRC = eflags;
209 void helper_aas(CPUX86State *env)
211 int icarry;
212 int al, ah, af;
213 int eflags;
215 eflags = cpu_cc_compute_all(env, CC_OP);
216 af = eflags & CC_A;
217 al = env->regs[R_EAX] & 0xff;
218 ah = (env->regs[R_EAX] >> 8) & 0xff;
220 icarry = (al < 6);
221 if (((al & 0x0f) > 9) || af) {
222 al = (al - 6) & 0x0f;
223 ah = (ah - 1 - icarry) & 0xff;
224 eflags |= CC_C | CC_A;
225 } else {
226 eflags &= ~(CC_C | CC_A);
227 al &= 0x0f;
229 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
230 CC_SRC = eflags;
233 void helper_daa(CPUX86State *env)
235 int old_al, al, af, cf;
236 int eflags;
238 eflags = cpu_cc_compute_all(env, CC_OP);
239 cf = eflags & CC_C;
240 af = eflags & CC_A;
241 old_al = al = env->regs[R_EAX] & 0xff;
243 eflags = 0;
244 if (((al & 0x0f) > 9) || af) {
245 al = (al + 6) & 0xff;
246 eflags |= CC_A;
248 if ((old_al > 0x99) || cf) {
249 al = (al + 0x60) & 0xff;
250 eflags |= CC_C;
252 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
253 /* well, speed is not an issue here, so we compute the flags by hand */
254 eflags |= (al == 0) << 6; /* zf */
255 eflags |= parity_table[al]; /* pf */
256 eflags |= (al & 0x80); /* sf */
257 CC_SRC = eflags;
260 void helper_das(CPUX86State *env)
262 int al, al1, af, cf;
263 int eflags;
265 eflags = cpu_cc_compute_all(env, CC_OP);
266 cf = eflags & CC_C;
267 af = eflags & CC_A;
268 al = env->regs[R_EAX] & 0xff;
270 eflags = 0;
271 al1 = al;
272 if (((al & 0x0f) > 9) || af) {
273 eflags |= CC_A;
274 if (al < 6 || cf) {
275 eflags |= CC_C;
277 al = (al - 6) & 0xff;
279 if ((al1 > 0x99) || cf) {
280 al = (al - 0x60) & 0xff;
281 eflags |= CC_C;
283 env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
284 /* well, speed is not an issue here, so we compute the flags by hand */
285 eflags |= (al == 0) << 6; /* zf */
286 eflags |= parity_table[al]; /* pf */
287 eflags |= (al & 0x80); /* sf */
288 CC_SRC = eflags;
291 #ifdef TARGET_X86_64
292 static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
294 *plow += a;
295 /* carry test */
296 if (*plow < a) {
297 (*phigh)++;
299 *phigh += b;
302 static void neg128(uint64_t *plow, uint64_t *phigh)
304 *plow = ~*plow;
305 *phigh = ~*phigh;
306 add128(plow, phigh, 1, 0);
309 /* return TRUE if overflow */
310 static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
312 uint64_t q, r, a1, a0;
313 int i, qb, ab;
315 a0 = *plow;
316 a1 = *phigh;
317 if (a1 == 0) {
318 q = a0 / b;
319 r = a0 % b;
320 *plow = q;
321 *phigh = r;
322 } else {
323 if (a1 >= b) {
324 return 1;
326 /* XXX: use a better algorithm */
327 for (i = 0; i < 64; i++) {
328 ab = a1 >> 63;
329 a1 = (a1 << 1) | (a0 >> 63);
330 if (ab || a1 >= b) {
331 a1 -= b;
332 qb = 1;
333 } else {
334 qb = 0;
336 a0 = (a0 << 1) | qb;
338 #if defined(DEBUG_MULDIV)
339 printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64
340 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
341 *phigh, *plow, b, a0, a1);
342 #endif
343 *plow = a0;
344 *phigh = a1;
346 return 0;
349 /* return TRUE if overflow */
350 static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
352 int sa, sb;
354 sa = ((int64_t)*phigh < 0);
355 if (sa) {
356 neg128(plow, phigh);
358 sb = (b < 0);
359 if (sb) {
360 b = -b;
362 if (div64(plow, phigh, b) != 0) {
363 return 1;
365 if (sa ^ sb) {
366 if (*plow > (1ULL << 63)) {
367 return 1;
369 *plow = -*plow;
370 } else {
371 if (*plow >= (1ULL << 63)) {
372 return 1;
375 if (sa) {
376 *phigh = -*phigh;
378 return 0;
381 void helper_divq_EAX(CPUX86State *env, target_ulong t0)
383 uint64_t r0, r1;
385 if (t0 == 0) {
386 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
388 r0 = env->regs[R_EAX];
389 r1 = env->regs[R_EDX];
390 if (div64(&r0, &r1, t0)) {
391 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
393 env->regs[R_EAX] = r0;
394 env->regs[R_EDX] = r1;
397 void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
399 uint64_t r0, r1;
401 if (t0 == 0) {
402 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
404 r0 = env->regs[R_EAX];
405 r1 = env->regs[R_EDX];
406 if (idiv64(&r0, &r1, t0)) {
407 raise_exception_ra(env, EXCP00_DIVZ, GETPC());
409 env->regs[R_EAX] = r0;
410 env->regs[R_EDX] = r1;
412 #endif
414 #if TARGET_LONG_BITS == 32
415 # define ctztl ctz32
416 # define clztl clz32
417 #else
418 # define ctztl ctz64
419 # define clztl clz64
420 #endif
422 target_ulong helper_pdep(target_ulong src, target_ulong mask)
424 target_ulong dest = 0;
425 int i, o;
427 for (i = 0; mask != 0; i++) {
428 o = ctztl(mask);
429 mask &= mask - 1;
430 dest |= ((src >> i) & 1) << o;
432 return dest;
435 target_ulong helper_pext(target_ulong src, target_ulong mask)
437 target_ulong dest = 0;
438 int i, o;
440 for (o = 0; mask != 0; o++) {
441 i = ctztl(mask);
442 mask &= mask - 1;
443 dest |= ((src >> i) & 1) << o;
445 return dest;
448 #define SHIFT 0
449 #include "shift_helper_template.h"
450 #undef SHIFT
452 #define SHIFT 1
453 #include "shift_helper_template.h"
454 #undef SHIFT
456 #define SHIFT 2
457 #include "shift_helper_template.h"
458 #undef SHIFT
460 #ifdef TARGET_X86_64
461 #define SHIFT 3
462 #include "shift_helper_template.h"
463 #undef SHIFT
464 #endif
466 /* Test that BIT is enabled in CR4. If not, raise an illegal opcode
467 exception. This reduces the requirements for rare CR4 bits being
468 mapped into HFLAGS. */
469 void helper_cr4_testbit(CPUX86State *env, uint32_t bit)
471 if (unlikely((env->cr[4] & bit) == 0)) {
472 raise_exception_ra(env, EXCP06_ILLOP, GETPC());
476 target_ulong HELPER(rdrand)(CPUX86State *env)
478 Error *err = NULL;
479 target_ulong ret;
481 if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
482 qemu_log_mask(LOG_UNIMP, "rdrand: Crypto failure: %s",
483 error_get_pretty(err));
484 error_free(err);
485 /* Failure clears CF and all other flags, and returns 0. */
486 env->cc_src = 0;
487 return 0;
490 /* Success sets CF and clears all others. */
491 env->cc_src = CC_C;
492 return ret;