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