qemu/target-i386/int_helper.c
<<
>>
Prefs
   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 */
  27static 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 */
  35static 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
  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    }
  57    q &= 0xff;
  58    r = (num % den) & 0xff;
  59    EAX = (EAX & ~0xffff) | (r << 8) | q;
  60}
  61
  62void 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
  80void 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
  99void 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
 118void 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
 137void 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 */
 159void 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
 170void 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
 181void 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
 205void 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
 229void 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
 256void 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
 288static 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
 298static 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 */
 306static 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 */
 346static 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
 377void 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
 388void 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
 399target_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
 410void 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
 426void 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 */
 444target_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
 458target_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
 479target_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
 501