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