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 "qemu/host-utils.h"
22#include "helper.h"
23
24//#define DEBUG_MULDIV
25
26/* modulo 17 table */
27static const uint8_t rclw_table[32] = {
28    0, 1, 2, 3, 4, 5, 6, 7,
29    8, 9,10,11,12,13,14,15,
30   16, 0, 1, 2, 3, 4, 5, 6,
31    7, 8, 9,10,11,12,13,14,
32};
33
34/* modulo 9 table */
35static const uint8_t rclb_table[32] = {
36    0, 1, 2, 3, 4, 5, 6, 7,
37    8, 0, 1, 2, 3, 4, 5, 6,
38    7, 8, 0, 1, 2, 3, 4, 5,
39    6, 7, 8, 0, 1, 2, 3, 4,
40};
41
42/* division, flags are undefined */
43
44void helper_divb_AL(CPUX86State *env, target_ulong t0)
45{
46    unsigned int num, den, q, r;
47
48    num = (EAX & 0xffff);
49    den = (t0 & 0xff);
50    if (den == 0) {
51        raise_exception(env, EXCP00_DIVZ);
52    }
53    q = (num / den);
54    if (q > 0xff)
55        raise_exception(env, EXCP00_DIVZ);
56    q &= 0xff;
57    r = (num % den) & 0xff;
58    EAX = (EAX & ~0xffff) | (r << 8) | q;
59}
60
61void helper_idivb_AL(CPUX86State *env, target_ulong t0)
62{
63    int num, den, q, r;
64
65    num = (int16_t)EAX;
66    den = (int8_t)t0;
67    if (den == 0) {
68        raise_exception(env, EXCP00_DIVZ);
69    }
70    q = (num / den);
71    if (q != (int8_t)q)
72        raise_exception(env, EXCP00_DIVZ);
73    q &= 0xff;
74    r = (num % den) & 0xff;
75    EAX = (EAX & ~0xffff) | (r << 8) | q;
76}
77
78void helper_divw_AX(CPUX86State *env, target_ulong t0)
79{
80    unsigned int num, den, q, r;
81
82    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
83    den = (t0 & 0xffff);
84    if (den == 0) {
85        raise_exception(env, EXCP00_DIVZ);
86    }
87    q = (num / den);
88    if (q > 0xffff)
89        raise_exception(env, EXCP00_DIVZ);
90    q &= 0xffff;
91    r = (num % den) & 0xffff;
92    EAX = (EAX & ~0xffff) | q;
93    EDX = (EDX & ~0xffff) | r;
94}
95
96void helper_idivw_AX(CPUX86State *env, target_ulong t0)
97{
98    int num, den, q, r;
99
100    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
101    den = (int16_t)t0;
102    if (den == 0) {
103        raise_exception(env, EXCP00_DIVZ);
104    }
105    q = (num / den);
106    if (q != (int16_t)q)
107        raise_exception(env, EXCP00_DIVZ);
108    q &= 0xffff;
109    r = (num % den) & 0xffff;
110    EAX = (EAX & ~0xffff) | q;
111    EDX = (EDX & ~0xffff) | r;
112}
113
114void helper_divl_EAX(CPUX86State *env, target_ulong t0)
115{
116    unsigned int den, r;
117    uint64_t num, q;
118
119    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
120    den = t0;
121    if (den == 0) {
122        raise_exception(env, EXCP00_DIVZ);
123    }
124    q = (num / den);
125    r = (num % den);
126    if (q > 0xffffffff)
127        raise_exception(env, EXCP00_DIVZ);
128    EAX = (uint32_t)q;
129    EDX = (uint32_t)r;
130}
131
132void helper_idivl_EAX(CPUX86State *env, target_ulong t0)
133{
134    int den, r;
135    int64_t num, q;
136
137    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
138    den = t0;
139    if (den == 0) {
140        raise_exception(env, EXCP00_DIVZ);
141    }
142    q = (num / den);
143    r = (num % den);
144    if (q != (int32_t)q)
145        raise_exception(env, EXCP00_DIVZ);
146    EAX = (uint32_t)q;
147    EDX = (uint32_t)r;
148}
149
150/* bcd */
151
152/* XXX: exception */
153void helper_aam(CPUX86State *env, int base)
154{
155    int al, ah;
156    al = EAX & 0xff;
157    ah = al / base;
158    al = al % base;
159    EAX = (EAX & ~0xffff) | al | (ah << 8);
160    CC_DST = al;
161}
162
163void helper_aad(CPUX86State *env, int base)
164{
165    int al, ah;
166    al = EAX & 0xff;
167    ah = (EAX >> 8) & 0xff;
168    al = ((ah * base) + al) & 0xff;
169    EAX = (EAX & ~0xffff) | al;
170    CC_DST = al;
171}
172
173void helper_aaa(CPUX86State *env)
174{
175    int icarry;
176    int al, ah, af;
177    int eflags;
178
179    eflags = helper_cc_compute_all(env, CC_OP);
180    af = eflags & CC_A;
181    al = EAX & 0xff;
182    ah = (EAX >> 8) & 0xff;
183
184    icarry = (al > 0xf9);
185    if (((al & 0x0f) > 9 ) || af) {
186        al = (al + 6) & 0x0f;
187        ah = (ah + 1 + icarry) & 0xff;
188        eflags |= CC_C | CC_A;
189    } else {
190        eflags &= ~(CC_C | CC_A);
191        al &= 0x0f;
192    }
193    EAX = (EAX & ~0xffff) | al | (ah << 8);
194    CC_SRC = eflags;
195}
196
197void helper_aas(CPUX86State *env)
198{
199    int icarry;
200    int al, ah, af;
201    int eflags;
202
203    eflags = helper_cc_compute_all(env, CC_OP);
204    af = eflags & CC_A;
205    al = EAX & 0xff;
206    ah = (EAX >> 8) & 0xff;
207
208    icarry = (al < 6);
209    if (((al & 0x0f) > 9 ) || af) {
210        al = (al - 6) & 0x0f;
211        ah = (ah - 1 - icarry) & 0xff;
212        eflags |= CC_C | CC_A;
213    } else {
214        eflags &= ~(CC_C | CC_A);
215        al &= 0x0f;
216    }
217    EAX = (EAX & ~0xffff) | al | (ah << 8);
218    CC_SRC = eflags;
219}
220
221void helper_daa(CPUX86State *env)
222{
223    int al, af, cf;
224    int eflags;
225
226    eflags = helper_cc_compute_all(env, CC_OP);
227    cf = eflags & CC_C;
228    af = eflags & CC_A;
229    al = EAX & 0xff;
230
231    eflags = 0;
232    if (((al & 0x0f) > 9 ) || af) {
233        al = (al + 6) & 0xff;
234        eflags |= CC_A;
235    }
236    if ((al > 0x9f) || cf) {
237        al = (al + 0x60) & 0xff;
238        eflags |= CC_C;
239    }
240    EAX = (EAX & ~0xff) | al;
241    /* well, speed is not an issue here, so we compute the flags by hand */
242    eflags |= (al == 0) << 6; /* zf */
243    eflags |= parity_table[al]; /* pf */
244    eflags |= (al & 0x80); /* sf */
245    CC_SRC = eflags;
246}
247
248void helper_das(CPUX86State *env)
249{
250    int al, al1, af, cf;
251    int eflags;
252
253    eflags = helper_cc_compute_all(env, CC_OP);
254    cf = eflags & CC_C;
255    af = eflags & CC_A;
256    al = EAX & 0xff;
257
258    eflags = 0;
259    al1 = al;
260    if (((al & 0x0f) > 9 ) || af) {
261        eflags |= CC_A;
262        if (al < 6 || cf)
263            eflags |= CC_C;
264        al = (al - 6) & 0xff;
265    }
266    if ((al1 > 0x99) || cf) {
267        al = (al - 0x60) & 0xff;
268        eflags |= CC_C;
269    }
270    EAX = (EAX & ~0xff) | al;
271    /* well, speed is not an issue here, so we compute the flags by hand */
272    eflags |= (al == 0) << 6; /* zf */
273    eflags |= parity_table[al]; /* pf */
274    eflags |= (al & 0x80); /* sf */
275    CC_SRC = eflags;
276}
277
278#ifdef TARGET_X86_64
279
280static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
281{
282    *plow += a;
283    /* carry test */
284    if (*plow < a)
285        (*phigh)++;
286    *phigh += b;
287}
288
289static void neg128(uint64_t *plow, uint64_t *phigh)
290{
291    *plow = ~ *plow;
292    *phigh = ~ *phigh;
293    add128(plow, phigh, 1, 0);
294}
295
296/* return TRUE if overflow */
297static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
298{
299    uint64_t q, r, a1, a0;
300    int i, qb, ab;
301
302    a0 = *plow;
303    a1 = *phigh;
304    if (a1 == 0) {
305        q = a0 / b;
306        r = a0 % b;
307        *plow = q;
308        *phigh = r;
309    } else {
310        if (a1 >= b)
311            return 1;
312        /* XXX: use a better algorithm */
313        for(i = 0; i < 64; i++) {
314            ab = a1 >> 63;
315            a1 = (a1 << 1) | (a0 >> 63);
316            if (ab || a1 >= b) {
317                a1 -= b;
318                qb = 1;
319            } else {
320                qb = 0;
321            }
322            a0 = (a0 << 1) | qb;
323        }
324#if defined(DEBUG_MULDIV)
325        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
326               *phigh, *plow, b, a0, a1);
327#endif
328        *plow = a0;
329        *phigh = a1;
330    }
331    return 0;
332}
333
334/* return TRUE if overflow */
335static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
336{
337    int sa, sb;
338    sa = ((int64_t)*phigh < 0);
339    if (sa)
340        neg128(plow, phigh);
341    sb = (b < 0);
342    if (sb)
343        b = -b;
344    if (div64(plow, phigh, b) != 0)
345        return 1;
346    if (sa ^ sb) {
347        if (*plow > (1ULL << 63))
348            return 1;
349        *plow = - *plow;
350    } else {
351        if (*plow >= (1ULL << 63))
352            return 1;
353    }
354    if (sa)
355        *phigh = - *phigh;
356    return 0;
357}
358
359void helper_mulq_EAX_T0(CPUX86State *env, target_ulong t0)
360{
361    uint64_t r0, r1;
362
363    mulu64(&r0, &r1, EAX, t0);
364    EAX = r0;
365    EDX = r1;
366    CC_DST = r0;
367    CC_SRC = r1;
368}
369
370void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0)
371{
372    uint64_t r0, r1;
373
374    muls64(&r0, &r1, EAX, t0);
375    EAX = r0;
376    EDX = r1;
377    CC_DST = r0;
378    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
379}
380
381target_ulong helper_imulq_T0_T1(CPUX86State *env, target_ulong t0, target_ulong t1)
382{
383    uint64_t r0, r1;
384
385    muls64(&r0, &r1, t0, t1);
386    CC_DST = r0;
387    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
388    return r0;
389}
390
391void helper_divq_EAX(CPUX86State *env, target_ulong t0)
392{
393    uint64_t r0, r1;
394    if (t0 == 0) {
395        raise_exception(env, EXCP00_DIVZ);
396    }
397    r0 = EAX;
398    r1 = EDX;
399    if (div64(&r0, &r1, t0))
400        raise_exception(env, EXCP00_DIVZ);
401    EAX = r0;
402    EDX = r1;
403}
404
405void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
406{
407    uint64_t r0, r1;
408    if (t0 == 0) {
409        raise_exception(env, EXCP00_DIVZ);
410    }
411    r0 = EAX;
412    r1 = EDX;
413    if (idiv64(&r0, &r1, t0))
414        raise_exception(env, EXCP00_DIVZ);
415    EAX = r0;
416    EDX = r1;
417}
418
419#endif
420
421#define SHIFT 0
422#include "shift_helper_template.h"
423#undef SHIFT
424
425#define SHIFT 1
426#include "shift_helper_template.h"
427#undef SHIFT
428
429#define SHIFT 2
430#include "shift_helper_template.h"
431#undef SHIFT
432
433#ifdef TARGET_X86_64
434#define SHIFT 3
435#include "shift_helper_template.h"
436#undef SHIFT
437#endif
438
439/* bit operations */
440target_ulong helper_bsf(target_ulong t0)
441{
442    int count;
443    target_ulong res;
444
445    res = t0;
446    count = 0;
447    while ((res & 1) == 0) {
448        count++;
449        res >>= 1;
450    }
451    return count;
452}
453
454target_ulong helper_bsr(target_ulong t0)
455{
456    int count;
457    target_ulong res, mask;
458
459    res = t0;
460    count = TARGET_LONG_BITS - 1;
461    mask = (target_ulong)1 << (TARGET_LONG_BITS - 1);
462    while ((res & mask) == 0) {
463        count--;
464        res <<= 1;
465    }
466    return count;
467}
468