Statistics
| Branch: | Revision:

root / target-i386 / int_helper.c @ 1de7afc9

History | View | Annotate | Download (10.4 kB)

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 9 table */
27
static const uint8_t rclb_table[32] = {
28
    0, 1, 2, 3, 4, 5, 6, 7,
29
    8, 0, 1, 2, 3, 4, 5, 6,
30
    7, 8, 0, 1, 2, 3, 4, 5,
31
    6, 7, 8, 0, 1, 2, 3, 4,
32
};
33

    
34
/* modulo 17 table */
35
static const uint8_t rclw_table[32] = {
36
    0, 1, 2, 3, 4, 5, 6, 7,
37
    8, 9, 10, 11, 12, 13, 14, 15,
38
    16, 0, 1, 2, 3, 4, 5, 6,
39
    7, 8, 9, 10, 11, 12, 13, 14,
40
};
41

    
42
/* division, flags are undefined */
43

    
44
void 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
    }
57
    q &= 0xff;
58
    r = (num % den) & 0xff;
59
    EAX = (EAX & ~0xffff) | (r << 8) | q;
60
}
61

    
62
void helper_idivb_AL(CPUX86State *env, target_ulong t0)
63
{
64
    int num, den, q, r;
65

    
66
    num = (int16_t)EAX;
67
    den = (int8_t)t0;
68
    if (den == 0) {
69
        raise_exception(env, EXCP00_DIVZ);
70
    }
71
    q = (num / den);
72
    if (q != (int8_t)q) {
73
        raise_exception(env, EXCP00_DIVZ);
74
    }
75
    q &= 0xff;
76
    r = (num % den) & 0xff;
77
    EAX = (EAX & ~0xffff) | (r << 8) | q;
78
}
79

    
80
void helper_divw_AX(CPUX86State *env, target_ulong t0)
81
{
82
    unsigned int num, den, q, r;
83

    
84
    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
85
    den = (t0 & 0xffff);
86
    if (den == 0) {
87
        raise_exception(env, EXCP00_DIVZ);
88
    }
89
    q = (num / den);
90
    if (q > 0xffff) {
91
        raise_exception(env, EXCP00_DIVZ);
92
    }
93
    q &= 0xffff;
94
    r = (num % den) & 0xffff;
95
    EAX = (EAX & ~0xffff) | q;
96
    EDX = (EDX & ~0xffff) | r;
97
}
98

    
99
void helper_idivw_AX(CPUX86State *env, target_ulong t0)
100
{
101
    int num, den, q, r;
102

    
103
    num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
104
    den = (int16_t)t0;
105
    if (den == 0) {
106
        raise_exception(env, EXCP00_DIVZ);
107
    }
108
    q = (num / den);
109
    if (q != (int16_t)q) {
110
        raise_exception(env, EXCP00_DIVZ);
111
    }
112
    q &= 0xffff;
113
    r = (num % den) & 0xffff;
114
    EAX = (EAX & ~0xffff) | q;
115
    EDX = (EDX & ~0xffff) | r;
116
}
117

    
118
void helper_divl_EAX(CPUX86State *env, target_ulong t0)
119
{
120
    unsigned int den, r;
121
    uint64_t num, q;
122

    
123
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
124
    den = t0;
125
    if (den == 0) {
126
        raise_exception(env, EXCP00_DIVZ);
127
    }
128
    q = (num / den);
129
    r = (num % den);
130
    if (q > 0xffffffff) {
131
        raise_exception(env, EXCP00_DIVZ);
132
    }
133
    EAX = (uint32_t)q;
134
    EDX = (uint32_t)r;
135
}
136

    
137
void helper_idivl_EAX(CPUX86State *env, target_ulong t0)
138
{
139
    int den, r;
140
    int64_t num, q;
141

    
142
    num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
143
    den = t0;
144
    if (den == 0) {
145
        raise_exception(env, EXCP00_DIVZ);
146
    }
147
    q = (num / den);
148
    r = (num % den);
149
    if (q != (int32_t)q) {
150
        raise_exception(env, EXCP00_DIVZ);
151
    }
152
    EAX = (uint32_t)q;
153
    EDX = (uint32_t)r;
154
}
155

    
156
/* bcd */
157

    
158
/* XXX: exception */
159
void helper_aam(CPUX86State *env, int base)
160
{
161
    int al, ah;
162

    
163
    al = EAX & 0xff;
164
    ah = al / base;
165
    al = al % base;
166
    EAX = (EAX & ~0xffff) | al | (ah << 8);
167
    CC_DST = al;
168
}
169

    
170
void helper_aad(CPUX86State *env, int base)
171
{
172
    int al, ah;
173

    
174
    al = EAX & 0xff;
175
    ah = (EAX >> 8) & 0xff;
176
    al = ((ah * base) + al) & 0xff;
177
    EAX = (EAX & ~0xffff) | al;
178
    CC_DST = al;
179
}
180

    
181
void helper_aaa(CPUX86State *env)
182
{
183
    int icarry;
184
    int al, ah, af;
185
    int eflags;
186

    
187
    eflags = cpu_cc_compute_all(env, CC_OP);
188
    af = eflags & CC_A;
189
    al = EAX & 0xff;
190
    ah = (EAX >> 8) & 0xff;
191

    
192
    icarry = (al > 0xf9);
193
    if (((al & 0x0f) > 9) || af) {
194
        al = (al + 6) & 0x0f;
195
        ah = (ah + 1 + icarry) & 0xff;
196
        eflags |= CC_C | CC_A;
197
    } else {
198
        eflags &= ~(CC_C | CC_A);
199
        al &= 0x0f;
200
    }
201
    EAX = (EAX & ~0xffff) | al | (ah << 8);
202
    CC_SRC = eflags;
203
}
204

    
205
void helper_aas(CPUX86State *env)
206
{
207
    int icarry;
208
    int al, ah, af;
209
    int eflags;
210

    
211
    eflags = cpu_cc_compute_all(env, CC_OP);
212
    af = eflags & CC_A;
213
    al = EAX & 0xff;
214
    ah = (EAX >> 8) & 0xff;
215

    
216
    icarry = (al < 6);
217
    if (((al & 0x0f) > 9) || af) {
218
        al = (al - 6) & 0x0f;
219
        ah = (ah - 1 - icarry) & 0xff;
220
        eflags |= CC_C | CC_A;
221
    } else {
222
        eflags &= ~(CC_C | CC_A);
223
        al &= 0x0f;
224
    }
225
    EAX = (EAX & ~0xffff) | al | (ah << 8);
226
    CC_SRC = eflags;
227
}
228

    
229
void helper_daa(CPUX86State *env)
230
{
231
    int old_al, al, af, cf;
232
    int eflags;
233

    
234
    eflags = cpu_cc_compute_all(env, CC_OP);
235
    cf = eflags & CC_C;
236
    af = eflags & CC_A;
237
    old_al = al = EAX & 0xff;
238

    
239
    eflags = 0;
240
    if (((al & 0x0f) > 9) || af) {
241
        al = (al + 6) & 0xff;
242
        eflags |= CC_A;
243
    }
244
    if ((old_al > 0x99) || cf) {
245
        al = (al + 0x60) & 0xff;
246
        eflags |= CC_C;
247
    }
248
    EAX = (EAX & ~0xff) | al;
249
    /* well, speed is not an issue here, so we compute the flags by hand */
250
    eflags |= (al == 0) << 6; /* zf */
251
    eflags |= parity_table[al]; /* pf */
252
    eflags |= (al & 0x80); /* sf */
253
    CC_SRC = eflags;
254
}
255

    
256
void helper_das(CPUX86State *env)
257
{
258
    int al, al1, af, cf;
259
    int eflags;
260

    
261
    eflags = cpu_cc_compute_all(env, CC_OP);
262
    cf = eflags & CC_C;
263
    af = eflags & CC_A;
264
    al = EAX & 0xff;
265

    
266
    eflags = 0;
267
    al1 = al;
268
    if (((al & 0x0f) > 9) || af) {
269
        eflags |= CC_A;
270
        if (al < 6 || cf) {
271
            eflags |= CC_C;
272
        }
273
        al = (al - 6) & 0xff;
274
    }
275
    if ((al1 > 0x99) || cf) {
276
        al = (al - 0x60) & 0xff;
277
        eflags |= CC_C;
278
    }
279
    EAX = (EAX & ~0xff) | al;
280
    /* well, speed is not an issue here, so we compute the flags by hand */
281
    eflags |= (al == 0) << 6; /* zf */
282
    eflags |= parity_table[al]; /* pf */
283
    eflags |= (al & 0x80); /* sf */
284
    CC_SRC = eflags;
285
}
286

    
287
#ifdef TARGET_X86_64
288
static void add128(uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
289
{
290
    *plow += a;
291
    /* carry test */
292
    if (*plow < a) {
293
        (*phigh)++;
294
    }
295
    *phigh += b;
296
}
297

    
298
static void neg128(uint64_t *plow, uint64_t *phigh)
299
{
300
    *plow = ~*plow;
301
    *phigh = ~*phigh;
302
    add128(plow, phigh, 1, 0);
303
}
304

    
305
/* return TRUE if overflow */
306
static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
307
{
308
    uint64_t q, r, a1, a0;
309
    int i, qb, ab;
310

    
311
    a0 = *plow;
312
    a1 = *phigh;
313
    if (a1 == 0) {
314
        q = a0 / b;
315
        r = a0 % b;
316
        *plow = q;
317
        *phigh = r;
318
    } else {
319
        if (a1 >= b) {
320
            return 1;
321
        }
322
        /* XXX: use a better algorithm */
323
        for (i = 0; i < 64; i++) {
324
            ab = a1 >> 63;
325
            a1 = (a1 << 1) | (a0 >> 63);
326
            if (ab || a1 >= b) {
327
                a1 -= b;
328
                qb = 1;
329
            } else {
330
                qb = 0;
331
            }
332
            a0 = (a0 << 1) | qb;
333
        }
334
#if defined(DEBUG_MULDIV)
335
        printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64
336
               ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
337
               *phigh, *plow, b, a0, a1);
338
#endif
339
        *plow = a0;
340
        *phigh = a1;
341
    }
342
    return 0;
343
}
344

    
345
/* return TRUE if overflow */
346
static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
347
{
348
    int sa, sb;
349

    
350
    sa = ((int64_t)*phigh < 0);
351
    if (sa) {
352
        neg128(plow, phigh);
353
    }
354
    sb = (b < 0);
355
    if (sb) {
356
        b = -b;
357
    }
358
    if (div64(plow, phigh, b) != 0) {
359
        return 1;
360
    }
361
    if (sa ^ sb) {
362
        if (*plow > (1ULL << 63)) {
363
            return 1;
364
        }
365
        *plow = -*plow;
366
    } else {
367
        if (*plow >= (1ULL << 63)) {
368
            return 1;
369
        }
370
    }
371
    if (sa) {
372
        *phigh = -*phigh;
373
    }
374
    return 0;
375
}
376

    
377
void helper_mulq_EAX_T0(CPUX86State *env, target_ulong t0)
378
{
379
    uint64_t r0, r1;
380

    
381
    mulu64(&r0, &r1, EAX, t0);
382
    EAX = r0;
383
    EDX = r1;
384
    CC_DST = r0;
385
    CC_SRC = r1;
386
}
387

    
388
void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0)
389
{
390
    uint64_t r0, r1;
391

    
392
    muls64(&r0, &r1, EAX, t0);
393
    EAX = r0;
394
    EDX = r1;
395
    CC_DST = r0;
396
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
397
}
398

    
399
target_ulong helper_imulq_T0_T1(CPUX86State *env, target_ulong t0,
400
                                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(CPUX86State *env, 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(CPUX86State *env, 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