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 */ 27 static 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 */ 35 static 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 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 q &= 0xff; 57 r = (num % den) & 0xff; 58 EAX = (EAX & ~0xffff) | (r << 8) | q; 59 } 60 61 void 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 78 void 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 96 void 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 114 void 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 132 void 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 */ 153 void 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 163 void 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 173 void 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 197 void 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 221 void 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 248 void 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 280 static 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 289 static 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 */ 297 static 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 */ 335 static 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 359 void 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 370 void 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 381 target_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 391 void 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 405 void 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 */ 440 target_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 454 target_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