xref: /qemu/target/i386/tcg/int_helper.c (revision abdcc5c8eff0879c76aeb9f16d0c13044bfecbda)
1d7582078SBlue Swirl /*
2d7582078SBlue Swirl  *  x86 integer helpers
3d7582078SBlue Swirl  *
4d7582078SBlue Swirl  *  Copyright (c) 2003 Fabrice Bellard
5d7582078SBlue Swirl  *
6d7582078SBlue Swirl  * This library is free software; you can redistribute it and/or
7d7582078SBlue Swirl  * modify it under the terms of the GNU Lesser General Public
8d7582078SBlue Swirl  * License as published by the Free Software Foundation; either
9d9ff33adSChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10d7582078SBlue Swirl  *
11d7582078SBlue Swirl  * This library is distributed in the hope that it will be useful,
12d7582078SBlue Swirl  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13d7582078SBlue Swirl  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14d7582078SBlue Swirl  * Lesser General Public License for more details.
15d7582078SBlue Swirl  *
16d7582078SBlue Swirl  * You should have received a copy of the GNU Lesser General Public
17d7582078SBlue Swirl  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18d7582078SBlue Swirl  */
19d7582078SBlue Swirl 
20b6a0aa05SPeter Maydell #include "qemu/osdep.h"
21cd617484SPhilippe Mathieu-Daudé #include "qemu/log.h"
22d7582078SBlue Swirl #include "cpu.h"
2363c91552SPaolo Bonzini #include "exec/exec-all.h"
241de7afc9SPaolo Bonzini #include "qemu/host-utils.h"
252ef6175aSRichard Henderson #include "exec/helper-proto.h"
26369fd5caSRichard Henderson #include "qapi/error.h"
27369fd5caSRichard Henderson #include "qemu/guest-random.h"
28ed69e831SClaudio Fontana #include "helper-tcg.h"
29d7582078SBlue Swirl 
30d7582078SBlue Swirl //#define DEBUG_MULDIV
31d7582078SBlue Swirl 
32d7582078SBlue Swirl /* division, flags are undefined */
33d7582078SBlue Swirl 
347923057bSBlue Swirl void helper_divb_AL(CPUX86State *env, target_ulong t0)
35d7582078SBlue Swirl {
36d7582078SBlue Swirl     unsigned int num, den, q, r;
37d7582078SBlue Swirl 
384b34e3adSliguang     num = (env->regs[R_EAX] & 0xffff);
39d7582078SBlue Swirl     den = (t0 & 0xff);
40d7582078SBlue Swirl     if (den == 0) {
41cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
42d7582078SBlue Swirl     }
43d7582078SBlue Swirl     q = (num / den);
44d7582078SBlue Swirl     if (q > 0xff) {
45cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
46d7582078SBlue Swirl     }
47d7582078SBlue Swirl     q &= 0xff;
48d7582078SBlue Swirl     r = (num % den) & 0xff;
494b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q;
50d7582078SBlue Swirl }
51d7582078SBlue Swirl 
527923057bSBlue Swirl void helper_idivb_AL(CPUX86State *env, target_ulong t0)
53d7582078SBlue Swirl {
54d7582078SBlue Swirl     int num, den, q, r;
55d7582078SBlue Swirl 
564b34e3adSliguang     num = (int16_t)env->regs[R_EAX];
57d7582078SBlue Swirl     den = (int8_t)t0;
58d7582078SBlue Swirl     if (den == 0) {
59cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
60d7582078SBlue Swirl     }
61d7582078SBlue Swirl     q = (num / den);
62d7582078SBlue Swirl     if (q != (int8_t)q) {
63cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
64d7582078SBlue Swirl     }
65d7582078SBlue Swirl     q &= 0xff;
66d7582078SBlue Swirl     r = (num % den) & 0xff;
674b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | (r << 8) | q;
68d7582078SBlue Swirl }
69d7582078SBlue Swirl 
707923057bSBlue Swirl void helper_divw_AX(CPUX86State *env, target_ulong t0)
71d7582078SBlue Swirl {
72d7582078SBlue Swirl     unsigned int num, den, q, r;
73d7582078SBlue Swirl 
7400f5e6f2Sliguang     num = (env->regs[R_EAX] & 0xffff) | ((env->regs[R_EDX] & 0xffff) << 16);
75d7582078SBlue Swirl     den = (t0 & 0xffff);
76d7582078SBlue Swirl     if (den == 0) {
77cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
78d7582078SBlue Swirl     }
79d7582078SBlue Swirl     q = (num / den);
80d7582078SBlue Swirl     if (q > 0xffff) {
81cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
82d7582078SBlue Swirl     }
83d7582078SBlue Swirl     q &= 0xffff;
84d7582078SBlue Swirl     r = (num % den) & 0xffff;
854b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | q;
8600f5e6f2Sliguang     env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r;
87d7582078SBlue Swirl }
88d7582078SBlue Swirl 
897923057bSBlue Swirl void helper_idivw_AX(CPUX86State *env, target_ulong t0)
90d7582078SBlue Swirl {
91d7582078SBlue Swirl     int num, den, q, r;
92d7582078SBlue Swirl 
9300f5e6f2Sliguang     num = (env->regs[R_EAX] & 0xffff) | ((env->regs[R_EDX] & 0xffff) << 16);
94d7582078SBlue Swirl     den = (int16_t)t0;
95d7582078SBlue Swirl     if (den == 0) {
96cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
97d7582078SBlue Swirl     }
98d7582078SBlue Swirl     q = (num / den);
99d7582078SBlue Swirl     if (q != (int16_t)q) {
100cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
101d7582078SBlue Swirl     }
102d7582078SBlue Swirl     q &= 0xffff;
103d7582078SBlue Swirl     r = (num % den) & 0xffff;
1044b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | q;
10500f5e6f2Sliguang     env->regs[R_EDX] = (env->regs[R_EDX] & ~0xffff) | r;
106d7582078SBlue Swirl }
107d7582078SBlue Swirl 
1087923057bSBlue Swirl void helper_divl_EAX(CPUX86State *env, target_ulong t0)
109d7582078SBlue Swirl {
110d7582078SBlue Swirl     unsigned int den, r;
111d7582078SBlue Swirl     uint64_t num, q;
112d7582078SBlue Swirl 
11300f5e6f2Sliguang     num = ((uint32_t)env->regs[R_EAX]) | ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
114d7582078SBlue Swirl     den = t0;
115d7582078SBlue Swirl     if (den == 0) {
116cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
117d7582078SBlue Swirl     }
118d7582078SBlue Swirl     q = (num / den);
119d7582078SBlue Swirl     r = (num % den);
120d7582078SBlue Swirl     if (q > 0xffffffff) {
121cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
122d7582078SBlue Swirl     }
1234b34e3adSliguang     env->regs[R_EAX] = (uint32_t)q;
12400f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)r;
125d7582078SBlue Swirl }
126d7582078SBlue Swirl 
1277923057bSBlue Swirl void helper_idivl_EAX(CPUX86State *env, target_ulong t0)
128d7582078SBlue Swirl {
129d7582078SBlue Swirl     int den, r;
130d7582078SBlue Swirl     int64_t num, q;
131d7582078SBlue Swirl 
13200f5e6f2Sliguang     num = ((uint32_t)env->regs[R_EAX]) | ((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
133d7582078SBlue Swirl     den = t0;
134d7582078SBlue Swirl     if (den == 0) {
135cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
136d7582078SBlue Swirl     }
137d7582078SBlue Swirl     q = (num / den);
138d7582078SBlue Swirl     r = (num % den);
139d7582078SBlue Swirl     if (q != (int32_t)q) {
140cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
141d7582078SBlue Swirl     }
1424b34e3adSliguang     env->regs[R_EAX] = (uint32_t)q;
14300f5e6f2Sliguang     env->regs[R_EDX] = (uint32_t)r;
144d7582078SBlue Swirl }
145d7582078SBlue Swirl 
146d7582078SBlue Swirl /* bcd */
147d7582078SBlue Swirl 
148ec568919SPaolo Bonzini target_ulong helper_aam(target_ulong al, target_ulong base)
149d7582078SBlue Swirl {
150ec568919SPaolo Bonzini     int ah;
151d7582078SBlue Swirl 
152ec568919SPaolo Bonzini     al &= 0xff;
153d7582078SBlue Swirl     ah = al / base;
154d7582078SBlue Swirl     al = al % base;
155ec568919SPaolo Bonzini     return al | (ah << 8);
156d7582078SBlue Swirl }
157d7582078SBlue Swirl 
158ec568919SPaolo Bonzini target_ulong helper_aad(target_ulong ax, target_ulong base)
159d7582078SBlue Swirl {
160d7582078SBlue Swirl     int al, ah;
161d7582078SBlue Swirl 
162ec568919SPaolo Bonzini     al = ax & 0xff;
163ec568919SPaolo Bonzini     ah = (ax >> 8) & 0xff;
164d7582078SBlue Swirl     al = ((ah * base) + al) & 0xff;
165ec568919SPaolo Bonzini     return al;
166d7582078SBlue Swirl }
167d7582078SBlue Swirl 
1687923057bSBlue Swirl void helper_aaa(CPUX86State *env)
169d7582078SBlue Swirl {
170d7582078SBlue Swirl     int icarry;
171d7582078SBlue Swirl     int al, ah, af;
172d7582078SBlue Swirl     int eflags;
173d7582078SBlue Swirl 
1742455e9cfSPaolo Bonzini     eflags = cpu_cc_compute_all(env);
175d7582078SBlue Swirl     af = eflags & CC_A;
1764b34e3adSliguang     al = env->regs[R_EAX] & 0xff;
1774b34e3adSliguang     ah = (env->regs[R_EAX] >> 8) & 0xff;
178d7582078SBlue Swirl 
179d7582078SBlue Swirl     icarry = (al > 0xf9);
180d7582078SBlue Swirl     if (((al & 0x0f) > 9) || af) {
181d7582078SBlue Swirl         al = (al + 6) & 0x0f;
182d7582078SBlue Swirl         ah = (ah + 1 + icarry) & 0xff;
183d7582078SBlue Swirl         eflags |= CC_C | CC_A;
184d7582078SBlue Swirl     } else {
185d7582078SBlue Swirl         eflags &= ~(CC_C | CC_A);
186d7582078SBlue Swirl         al &= 0x0f;
187d7582078SBlue Swirl     }
1884b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
189d7582078SBlue Swirl     CC_SRC = eflags;
190*abdcc5c8SPaolo Bonzini     CC_OP = CC_OP_EFLAGS;
191d7582078SBlue Swirl }
192d7582078SBlue Swirl 
1937923057bSBlue Swirl void helper_aas(CPUX86State *env)
194d7582078SBlue Swirl {
195d7582078SBlue Swirl     int icarry;
196d7582078SBlue Swirl     int al, ah, af;
197d7582078SBlue Swirl     int eflags;
198d7582078SBlue Swirl 
1992455e9cfSPaolo Bonzini     eflags = cpu_cc_compute_all(env);
200d7582078SBlue Swirl     af = eflags & CC_A;
2014b34e3adSliguang     al = env->regs[R_EAX] & 0xff;
2024b34e3adSliguang     ah = (env->regs[R_EAX] >> 8) & 0xff;
203d7582078SBlue Swirl 
204d7582078SBlue Swirl     icarry = (al < 6);
205d7582078SBlue Swirl     if (((al & 0x0f) > 9) || af) {
206d7582078SBlue Swirl         al = (al - 6) & 0x0f;
207d7582078SBlue Swirl         ah = (ah - 1 - icarry) & 0xff;
208d7582078SBlue Swirl         eflags |= CC_C | CC_A;
209d7582078SBlue Swirl     } else {
210d7582078SBlue Swirl         eflags &= ~(CC_C | CC_A);
211d7582078SBlue Swirl         al &= 0x0f;
212d7582078SBlue Swirl     }
2134b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xffff) | al | (ah << 8);
214d7582078SBlue Swirl     CC_SRC = eflags;
215*abdcc5c8SPaolo Bonzini     CC_OP = CC_OP_EFLAGS;
216d7582078SBlue Swirl }
217d7582078SBlue Swirl 
2187923057bSBlue Swirl void helper_daa(CPUX86State *env)
219d7582078SBlue Swirl {
220d7582078SBlue Swirl     int old_al, al, af, cf;
221d7582078SBlue Swirl     int eflags;
222d7582078SBlue Swirl 
2232455e9cfSPaolo Bonzini     eflags = cpu_cc_compute_all(env);
224d7582078SBlue Swirl     cf = eflags & CC_C;
225d7582078SBlue Swirl     af = eflags & CC_A;
2264b34e3adSliguang     old_al = al = env->regs[R_EAX] & 0xff;
227d7582078SBlue Swirl 
228d7582078SBlue Swirl     eflags = 0;
229d7582078SBlue Swirl     if (((al & 0x0f) > 9) || af) {
230d7582078SBlue Swirl         al = (al + 6) & 0xff;
231d7582078SBlue Swirl         eflags |= CC_A;
232d7582078SBlue Swirl     }
233d7582078SBlue Swirl     if ((old_al > 0x99) || cf) {
234d7582078SBlue Swirl         al = (al + 0x60) & 0xff;
235d7582078SBlue Swirl         eflags |= CC_C;
236d7582078SBlue Swirl     }
2374b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
238d7582078SBlue Swirl     /* well, speed is not an issue here, so we compute the flags by hand */
239d7582078SBlue Swirl     eflags |= (al == 0) << 6; /* zf */
240d7582078SBlue Swirl     eflags |= parity_table[al]; /* pf */
241d7582078SBlue Swirl     eflags |= (al & 0x80); /* sf */
242d7582078SBlue Swirl     CC_SRC = eflags;
243*abdcc5c8SPaolo Bonzini     CC_OP = CC_OP_EFLAGS;
244d7582078SBlue Swirl }
245d7582078SBlue Swirl 
2467923057bSBlue Swirl void helper_das(CPUX86State *env)
247d7582078SBlue Swirl {
248d7582078SBlue Swirl     int al, al1, af, cf;
249d7582078SBlue Swirl     int eflags;
250d7582078SBlue Swirl 
2512455e9cfSPaolo Bonzini     eflags = cpu_cc_compute_all(env);
252d7582078SBlue Swirl     cf = eflags & CC_C;
253d7582078SBlue Swirl     af = eflags & CC_A;
2544b34e3adSliguang     al = env->regs[R_EAX] & 0xff;
255d7582078SBlue Swirl 
256d7582078SBlue Swirl     eflags = 0;
257d7582078SBlue Swirl     al1 = al;
258d7582078SBlue Swirl     if (((al & 0x0f) > 9) || af) {
259d7582078SBlue Swirl         eflags |= CC_A;
260d7582078SBlue Swirl         if (al < 6 || cf) {
261d7582078SBlue Swirl             eflags |= CC_C;
262d7582078SBlue Swirl         }
263d7582078SBlue Swirl         al = (al - 6) & 0xff;
264d7582078SBlue Swirl     }
265d7582078SBlue Swirl     if ((al1 > 0x99) || cf) {
266d7582078SBlue Swirl         al = (al - 0x60) & 0xff;
267d7582078SBlue Swirl         eflags |= CC_C;
268d7582078SBlue Swirl     }
2694b34e3adSliguang     env->regs[R_EAX] = (env->regs[R_EAX] & ~0xff) | al;
270d7582078SBlue Swirl     /* well, speed is not an issue here, so we compute the flags by hand */
271d7582078SBlue Swirl     eflags |= (al == 0) << 6; /* zf */
272d7582078SBlue Swirl     eflags |= parity_table[al]; /* pf */
273d7582078SBlue Swirl     eflags |= (al & 0x80); /* sf */
274d7582078SBlue Swirl     CC_SRC = eflags;
275*abdcc5c8SPaolo Bonzini     CC_OP = CC_OP_EFLAGS;
276d7582078SBlue Swirl }
277d7582078SBlue Swirl 
278d7582078SBlue Swirl #ifdef TARGET_X86_64
279d7582078SBlue Swirl static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
280d7582078SBlue Swirl {
281d7582078SBlue Swirl     *plow += a;
282d7582078SBlue Swirl     /* carry test */
283d7582078SBlue Swirl     if (*plow < a) {
284d7582078SBlue Swirl         (*phigh)++;
285d7582078SBlue Swirl     }
286d7582078SBlue Swirl     *phigh += b;
287d7582078SBlue Swirl }
288d7582078SBlue Swirl 
289d7582078SBlue Swirl static void neg128(uint64_t *plow, uint64_t *phigh)
290d7582078SBlue Swirl {
291d7582078SBlue Swirl     *plow = ~*plow;
292d7582078SBlue Swirl     *phigh = ~*phigh;
293d7582078SBlue Swirl     add128(plow, phigh, 1, 0);
294d7582078SBlue Swirl }
295d7582078SBlue Swirl 
296d7582078SBlue Swirl /* return TRUE if overflow */
297d7582078SBlue Swirl static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
298d7582078SBlue Swirl {
299d7582078SBlue Swirl     uint64_t q, r, a1, a0;
300d7582078SBlue Swirl     int i, qb, ab;
301d7582078SBlue Swirl 
302d7582078SBlue Swirl     a0 = *plow;
303d7582078SBlue Swirl     a1 = *phigh;
304d7582078SBlue Swirl     if (a1 == 0) {
305d7582078SBlue Swirl         q = a0 / b;
306d7582078SBlue Swirl         r = a0 % b;
307d7582078SBlue Swirl         *plow = q;
308d7582078SBlue Swirl         *phigh = r;
309d7582078SBlue Swirl     } else {
310d7582078SBlue Swirl         if (a1 >= b) {
311d7582078SBlue Swirl             return 1;
312d7582078SBlue Swirl         }
313d7582078SBlue Swirl         /* XXX: use a better algorithm */
314d7582078SBlue Swirl         for (i = 0; i < 64; i++) {
315d7582078SBlue Swirl             ab = a1 >> 63;
316d7582078SBlue Swirl             a1 = (a1 << 1) | (a0 >> 63);
317d7582078SBlue Swirl             if (ab || a1 >= b) {
318d7582078SBlue Swirl                 a1 -= b;
319d7582078SBlue Swirl                 qb = 1;
320d7582078SBlue Swirl             } else {
321d7582078SBlue Swirl                 qb = 0;
322d7582078SBlue Swirl             }
323d7582078SBlue Swirl             a0 = (a0 << 1) | qb;
324d7582078SBlue Swirl         }
325d7582078SBlue Swirl #if defined(DEBUG_MULDIV)
326d7582078SBlue Swirl         printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64
327d7582078SBlue Swirl                ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
328d7582078SBlue Swirl                *phigh, *plow, b, a0, a1);
329d7582078SBlue Swirl #endif
330d7582078SBlue Swirl         *plow = a0;
331d7582078SBlue Swirl         *phigh = a1;
332d7582078SBlue Swirl     }
333d7582078SBlue Swirl     return 0;
334d7582078SBlue Swirl }
335d7582078SBlue Swirl 
336d7582078SBlue Swirl /* return TRUE if overflow */
337d7582078SBlue Swirl static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
338d7582078SBlue Swirl {
339d7582078SBlue Swirl     int sa, sb;
340d7582078SBlue Swirl 
341d7582078SBlue Swirl     sa = ((int64_t)*phigh < 0);
342d7582078SBlue Swirl     if (sa) {
343d7582078SBlue Swirl         neg128(plow, phigh);
344d7582078SBlue Swirl     }
345d7582078SBlue Swirl     sb = (b < 0);
346d7582078SBlue Swirl     if (sb) {
347d7582078SBlue Swirl         b = -b;
348d7582078SBlue Swirl     }
349d7582078SBlue Swirl     if (div64(plow, phigh, b) != 0) {
350d7582078SBlue Swirl         return 1;
351d7582078SBlue Swirl     }
352d7582078SBlue Swirl     if (sa ^ sb) {
353d7582078SBlue Swirl         if (*plow > (1ULL << 63)) {
354d7582078SBlue Swirl             return 1;
355d7582078SBlue Swirl         }
356d7582078SBlue Swirl         *plow = -*plow;
357d7582078SBlue Swirl     } else {
358d7582078SBlue Swirl         if (*plow >= (1ULL << 63)) {
359d7582078SBlue Swirl             return 1;
360d7582078SBlue Swirl         }
361d7582078SBlue Swirl     }
362d7582078SBlue Swirl     if (sa) {
363d7582078SBlue Swirl         *phigh = -*phigh;
364d7582078SBlue Swirl     }
365d7582078SBlue Swirl     return 0;
366d7582078SBlue Swirl }
367d7582078SBlue Swirl 
3687923057bSBlue Swirl void helper_divq_EAX(CPUX86State *env, target_ulong t0)
369d7582078SBlue Swirl {
370d7582078SBlue Swirl     uint64_t r0, r1;
371d7582078SBlue Swirl 
372d7582078SBlue Swirl     if (t0 == 0) {
373cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
374d7582078SBlue Swirl     }
3754b34e3adSliguang     r0 = env->regs[R_EAX];
37600f5e6f2Sliguang     r1 = env->regs[R_EDX];
377d7582078SBlue Swirl     if (div64(&r0, &r1, t0)) {
378cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
379d7582078SBlue Swirl     }
3804b34e3adSliguang     env->regs[R_EAX] = r0;
38100f5e6f2Sliguang     env->regs[R_EDX] = r1;
382d7582078SBlue Swirl }
383d7582078SBlue Swirl 
3847923057bSBlue Swirl void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
385d7582078SBlue Swirl {
386d7582078SBlue Swirl     uint64_t r0, r1;
387d7582078SBlue Swirl 
388d7582078SBlue Swirl     if (t0 == 0) {
389cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
390d7582078SBlue Swirl     }
3914b34e3adSliguang     r0 = env->regs[R_EAX];
39200f5e6f2Sliguang     r1 = env->regs[R_EDX];
393d7582078SBlue Swirl     if (idiv64(&r0, &r1, t0)) {
394cc33c5d6SPavel Dovgalyuk         raise_exception_ra(env, EXCP00_DIVZ, GETPC());
395d7582078SBlue Swirl     }
3964b34e3adSliguang     env->regs[R_EAX] = r0;
39700f5e6f2Sliguang     env->regs[R_EDX] = r1;
398d7582078SBlue Swirl }
399d7582078SBlue Swirl #endif
400d7582078SBlue Swirl 
401f1300734SRichard Henderson #if TARGET_LONG_BITS == 32
402f1300734SRichard Henderson # define ctztl  ctz32
403f1300734SRichard Henderson # define clztl  clz32
404f1300734SRichard Henderson #else
405f1300734SRichard Henderson # define ctztl  ctz64
406f1300734SRichard Henderson # define clztl  clz64
407f1300734SRichard Henderson #endif
408f1300734SRichard Henderson 
4090592f74aSRichard Henderson target_ulong helper_pdep(target_ulong src, target_ulong mask)
4100592f74aSRichard Henderson {
4110592f74aSRichard Henderson     target_ulong dest = 0;
4120592f74aSRichard Henderson     int i, o;
4130592f74aSRichard Henderson 
4140592f74aSRichard Henderson     for (i = 0; mask != 0; i++) {
4150592f74aSRichard Henderson         o = ctztl(mask);
4160592f74aSRichard Henderson         mask &= mask - 1;
4170592f74aSRichard Henderson         dest |= ((src >> i) & 1) << o;
4180592f74aSRichard Henderson     }
4190592f74aSRichard Henderson     return dest;
4200592f74aSRichard Henderson }
4210592f74aSRichard Henderson 
4220592f74aSRichard Henderson target_ulong helper_pext(target_ulong src, target_ulong mask)
4230592f74aSRichard Henderson {
4240592f74aSRichard Henderson     target_ulong dest = 0;
4250592f74aSRichard Henderson     int i, o;
4260592f74aSRichard Henderson 
4270592f74aSRichard Henderson     for (o = 0; mask != 0; o++) {
4280592f74aSRichard Henderson         i = ctztl(mask);
4290592f74aSRichard Henderson         mask &= mask - 1;
4300592f74aSRichard Henderson         dest |= ((src >> i) & 1) << o;
4310592f74aSRichard Henderson     }
4320592f74aSRichard Henderson     return dest;
4330592f74aSRichard Henderson }
4340592f74aSRichard Henderson 
43507929f2aSRichard Henderson /* Test that BIT is enabled in CR4.  If not, raise an illegal opcode
43607929f2aSRichard Henderson    exception.  This reduces the requirements for rare CR4 bits being
43707929f2aSRichard Henderson    mapped into HFLAGS.  */
43807929f2aSRichard Henderson void helper_cr4_testbit(CPUX86State *env, uint32_t bit)
43907929f2aSRichard Henderson {
44007929f2aSRichard Henderson     if (unlikely((env->cr[4] & bit) == 0)) {
44107929f2aSRichard Henderson         raise_exception_ra(env, EXCP06_ILLOP, GETPC());
44207929f2aSRichard Henderson     }
44307929f2aSRichard Henderson }
444369fd5caSRichard Henderson 
445369fd5caSRichard Henderson target_ulong HELPER(rdrand)(CPUX86State *env)
446369fd5caSRichard Henderson {
447369fd5caSRichard Henderson     Error *err = NULL;
448369fd5caSRichard Henderson     target_ulong ret;
449369fd5caSRichard Henderson 
450369fd5caSRichard Henderson     if (qemu_guest_getrandom(&ret, sizeof(ret), &err) < 0) {
451369fd5caSRichard Henderson         qemu_log_mask(LOG_UNIMP, "rdrand: Crypto failure: %s",
452369fd5caSRichard Henderson                       error_get_pretty(err));
453369fd5caSRichard Henderson         error_free(err);
454369fd5caSRichard Henderson         /* Failure clears CF and all other flags, and returns 0.  */
455369fd5caSRichard Henderson         env->cc_src = 0;
456*abdcc5c8SPaolo Bonzini         ret = 0;
457*abdcc5c8SPaolo Bonzini     } else {
458369fd5caSRichard Henderson         /* Success sets CF and clears all others.  */
459369fd5caSRichard Henderson         env->cc_src = CC_C;
460*abdcc5c8SPaolo Bonzini     }
461*abdcc5c8SPaolo Bonzini     env->cc_op = CC_OP_EFLAGS;
462369fd5caSRichard Henderson     return ret;
463369fd5caSRichard Henderson }
464