Statistics
| Branch: | Revision:

root / target-i386 / int_helper.c @ 76f13133

History | View | Annotate | Download (10.6 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
target_ulong helper_umulh(target_ulong t0, target_ulong t1)
389
{
390
    uint64_t h, l;
391
    mulu64(&l, &h, t0, t1);
392
    return h;
393
}
394

    
395
void helper_imulq_EAX_T0(CPUX86State *env, target_ulong t0)
396
{
397
    uint64_t r0, r1;
398

    
399
    muls64(&r0, &r1, EAX, t0);
400
    EAX = r0;
401
    EDX = r1;
402
    CC_DST = r0;
403
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
404
}
405

    
406
target_ulong helper_imulq_T0_T1(CPUX86State *env, target_ulong t0,
407
                                target_ulong t1)
408
{
409
    uint64_t r0, r1;
410

    
411
    muls64(&r0, &r1, t0, t1);
412
    CC_DST = r0;
413
    CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
414
    return r0;
415
}
416

    
417
void helper_divq_EAX(CPUX86State *env, target_ulong t0)
418
{
419
    uint64_t r0, r1;
420

    
421
    if (t0 == 0) {
422
        raise_exception(env, EXCP00_DIVZ);
423
    }
424
    r0 = EAX;
425
    r1 = EDX;
426
    if (div64(&r0, &r1, t0)) {
427
        raise_exception(env, EXCP00_DIVZ);
428
    }
429
    EAX = r0;
430
    EDX = r1;
431
}
432

    
433
void helper_idivq_EAX(CPUX86State *env, target_ulong t0)
434
{
435
    uint64_t r0, r1;
436

    
437
    if (t0 == 0) {
438
        raise_exception(env, EXCP00_DIVZ);
439
    }
440
    r0 = EAX;
441
    r1 = EDX;
442
    if (idiv64(&r0, &r1, t0)) {
443
        raise_exception(env, EXCP00_DIVZ);
444
    }
445
    EAX = r0;
446
    EDX = r1;
447
}
448
#endif
449

    
450
#if TARGET_LONG_BITS == 32
451
# define ctztl  ctz32
452
# define clztl  clz32
453
#else
454
# define ctztl  ctz64
455
# define clztl  clz64
456
#endif
457

    
458
/* bit operations */
459
target_ulong helper_ctz(target_ulong t0)
460
{
461
    return ctztl(t0);
462
}
463

    
464
target_ulong helper_clz(target_ulong t0)
465
{
466
    return clztl(t0);
467
}
468

    
469
target_ulong helper_pdep(target_ulong src, target_ulong mask)
470
{
471
    target_ulong dest = 0;
472
    int i, o;
473

    
474
    for (i = 0; mask != 0; i++) {
475
        o = ctztl(mask);
476
        mask &= mask - 1;
477
        dest |= ((src >> i) & 1) << o;
478
    }
479
    return dest;
480
}
481

    
482
target_ulong helper_pext(target_ulong src, target_ulong mask)
483
{
484
    target_ulong dest = 0;
485
    int i, o;
486

    
487
    for (o = 0; mask != 0; o++) {
488
        i = ctztl(mask);
489
        mask &= mask - 1;
490
        dest |= ((src >> i) & 1) << o;
491
    }
492
    return dest;
493
}
494

    
495
#define SHIFT 0
496
#include "shift_helper_template.h"
497
#undef SHIFT
498

    
499
#define SHIFT 1
500
#include "shift_helper_template.h"
501
#undef SHIFT
502

    
503
#define SHIFT 2
504
#include "shift_helper_template.h"
505
#undef SHIFT
506

    
507
#ifdef TARGET_X86_64
508
#define SHIFT 3
509
#include "shift_helper_template.h"
510
#undef SHIFT
511
#endif