Commit a35f3ec76be8e0a5424349831127e538c6b91ef5
1 parent
34c6f050
3DNow! instruction set emulation
(Michael Tross) git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4180 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
4 changed files
with
246 additions
and
10 deletions
target-i386/cpu.h
| ... | ... | @@ -428,8 +428,9 @@ typedef union { |
| 428 | 428 | |
| 429 | 429 | typedef union { |
| 430 | 430 | uint8_t _b[8]; |
| 431 | - uint16_t _w[2]; | |
| 432 | - uint32_t _l[1]; | |
| 431 | + uint16_t _w[4]; | |
| 432 | + uint32_t _l[2]; | |
| 433 | + float32 _s[2]; | |
| 433 | 434 | uint64_t q; |
| 434 | 435 | } MMXReg; |
| 435 | 436 | |
| ... | ... | @@ -444,6 +445,7 @@ typedef union { |
| 444 | 445 | #define MMX_B(n) _b[7 - (n)] |
| 445 | 446 | #define MMX_W(n) _w[3 - (n)] |
| 446 | 447 | #define MMX_L(n) _l[1 - (n)] |
| 448 | +#define MMX_S(n) _s[1 - (n)] | |
| 447 | 449 | #else |
| 448 | 450 | #define XMM_B(n) _b[n] |
| 449 | 451 | #define XMM_W(n) _w[n] |
| ... | ... | @@ -455,6 +457,7 @@ typedef union { |
| 455 | 457 | #define MMX_B(n) _b[n] |
| 456 | 458 | #define MMX_W(n) _w[n] |
| 457 | 459 | #define MMX_L(n) _l[n] |
| 460 | +#define MMX_S(n) _s[n] | |
| 458 | 461 | #endif |
| 459 | 462 | #define MMX_Q(n) q |
| 460 | 463 | |
| ... | ... | @@ -520,6 +523,7 @@ typedef struct CPUX86State { |
| 520 | 523 | int64_t i64; |
| 521 | 524 | } fp_convert; |
| 522 | 525 | |
| 526 | + float_status mmx_status; /* for 3DNow! float ops */ | |
| 523 | 527 | float_status sse_status; |
| 524 | 528 | uint32_t mxcsr; |
| 525 | 529 | XMMReg xmm_regs[CPU_NB_REGS]; | ... | ... |
target-i386/helper2.c
| ... | ... | @@ -150,7 +150,8 @@ static x86_def_t x86_defs[] = { |
| 150 | 150 | CPUID_PSE36, |
| 151 | 151 | .ext_features = CPUID_EXT_SSE3, |
| 152 | 152 | .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | |
| 153 | - CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX, | |
| 153 | + CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX | | |
| 154 | + CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT, | |
| 154 | 155 | .ext3_features = CPUID_EXT3_SVM, |
| 155 | 156 | .xlevel = 0x8000000A, |
| 156 | 157 | }, |
| ... | ... | @@ -201,6 +202,19 @@ static x86_def_t x86_defs[] = { |
| 201 | 202 | .features = 0x0383F9FF, |
| 202 | 203 | .xlevel = 0, |
| 203 | 204 | }, |
| 205 | + { | |
| 206 | + .name = "athlon", | |
| 207 | + .level = 2, | |
| 208 | + .vendor1 = 0x68747541, /* "Auth" */ | |
| 209 | + .vendor2 = 0x69746e65, /* "enti" */ | |
| 210 | + .vendor3 = 0x444d4163, /* "cAMD" */ | |
| 211 | + .family = 6, | |
| 212 | + .model = 2, | |
| 213 | + .stepping = 3, | |
| 214 | + .features = PPRO_FEATURES | PPRO_FEATURES | CPUID_PSE36 | CPUID_VME | CPUID_MTRR | CPUID_MCA, | |
| 215 | + .ext2_features = (PPRO_FEATURES & 0x0183F3FF) | CPUID_EXT2_MMXEXT | CPUID_EXT2_3DNOW | CPUID_EXT2_3DNOWEXT, | |
| 216 | + .xlevel = 0x80000008, | |
| 217 | + }, | |
| 204 | 218 | }; |
| 205 | 219 | |
| 206 | 220 | static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model) | ... | ... |
target-i386/ops_sse.h
| 1 | 1 | /* |
| 2 | - * MMX/SSE/SSE2/PNI support | |
| 2 | + * MMX/3DNow!/SSE/SSE2/SSE3/PNI support | |
| 3 | 3 | * |
| 4 | 4 | * Copyright (c) 2005 Fabrice Bellard |
| 5 | 5 | * |
| ... | ... | @@ -409,6 +409,7 @@ static inline int satsw(int x) |
| 409 | 409 | #define FCMPEQ(a, b) (a) == (b) ? -1 : 0 |
| 410 | 410 | |
| 411 | 411 | #define FMULLW(a, b) (a) * (b) |
| 412 | +#define FMULHRW(a, b) ((int16_t)(a) * (int16_t)(b) + 0x8000) >> 16 | |
| 412 | 413 | #define FMULHUW(a, b) (a) * (b) >> 16 |
| 413 | 414 | #define FMULHW(a, b) (int16_t)(a) * (int16_t)(b) >> 16 |
| 414 | 415 | |
| ... | ... | @@ -455,6 +456,9 @@ SSE_OP_W(op_pcmpeqw, FCMPEQ) |
| 455 | 456 | SSE_OP_L(op_pcmpeql, FCMPEQ) |
| 456 | 457 | |
| 457 | 458 | SSE_OP_W(op_pmullw, FMULLW) |
| 459 | +#if SHIFT == 0 | |
| 460 | +SSE_OP_W(op_pmulhrw, FMULHRW) | |
| 461 | +#endif | |
| 458 | 462 | SSE_OP_W(op_pmulhuw, FMULHUW) |
| 459 | 463 | SSE_OP_W(op_pmulhw, FMULHW) |
| 460 | 464 | |
| ... | ... | @@ -1383,6 +1387,175 @@ void OPPROTO glue(op_punpck ## base_name ## qdq, SUFFIX) (void) \ |
| 1383 | 1387 | UNPCK_OP(l, 0) |
| 1384 | 1388 | UNPCK_OP(h, 1) |
| 1385 | 1389 | |
| 1390 | +/* 3DNow! float ops */ | |
| 1391 | +#if SHIFT == 0 | |
| 1392 | +void OPPROTO op_pi2fd(void) | |
| 1393 | +{ | |
| 1394 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1395 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1396 | + d->MMX_S(0) = int32_to_float32(s->MMX_L(0), &env->mmx_status); | |
| 1397 | + d->MMX_S(1) = int32_to_float32(s->MMX_L(1), &env->mmx_status); | |
| 1398 | +} | |
| 1399 | + | |
| 1400 | +void OPPROTO op_pi2fw(void) | |
| 1401 | +{ | |
| 1402 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1403 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1404 | + d->MMX_S(0) = int32_to_float32((int16_t)s->MMX_W(0), &env->mmx_status); | |
| 1405 | + d->MMX_S(1) = int32_to_float32((int16_t)s->MMX_W(2), &env->mmx_status); | |
| 1406 | +} | |
| 1407 | + | |
| 1408 | +void OPPROTO op_pf2id(void) | |
| 1409 | +{ | |
| 1410 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1411 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1412 | + d->MMX_L(0) = float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status); | |
| 1413 | + d->MMX_L(1) = float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status); | |
| 1414 | +} | |
| 1415 | + | |
| 1416 | +void OPPROTO op_pf2iw(void) | |
| 1417 | +{ | |
| 1418 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1419 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1420 | + d->MMX_L(0) = satsw(float32_to_int32_round_to_zero(s->MMX_S(0), &env->mmx_status)); | |
| 1421 | + d->MMX_L(1) = satsw(float32_to_int32_round_to_zero(s->MMX_S(1), &env->mmx_status)); | |
| 1422 | +} | |
| 1423 | + | |
| 1424 | +void OPPROTO op_pfacc(void) | |
| 1425 | +{ | |
| 1426 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1427 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1428 | + MMXReg r; | |
| 1429 | + r.MMX_S(0) = float32_add(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); | |
| 1430 | + r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); | |
| 1431 | + *d = r; | |
| 1432 | +} | |
| 1433 | + | |
| 1434 | +void OPPROTO op_pfadd(void) | |
| 1435 | +{ | |
| 1436 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1437 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1438 | + d->MMX_S(0) = float32_add(d->MMX_S(0), s->MMX_S(0), &env->mmx_status); | |
| 1439 | + d->MMX_S(1) = float32_add(d->MMX_S(1), s->MMX_S(1), &env->mmx_status); | |
| 1440 | +} | |
| 1441 | + | |
| 1442 | +void OPPROTO op_pfcmpeq(void) | |
| 1443 | +{ | |
| 1444 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1445 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1446 | + d->MMX_L(0) = float32_eq(d->MMX_S(0), s->MMX_S(0), &env->mmx_status) ? -1 : 0; | |
| 1447 | + d->MMX_L(1) = float32_eq(d->MMX_S(1), s->MMX_S(1), &env->mmx_status) ? -1 : 0; | |
| 1448 | +} | |
| 1449 | + | |
| 1450 | +void OPPROTO op_pfcmpge(void) | |
| 1451 | +{ | |
| 1452 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1453 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1454 | + d->MMX_L(0) = float32_le(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0; | |
| 1455 | + d->MMX_L(1) = float32_le(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0; | |
| 1456 | +} | |
| 1457 | + | |
| 1458 | +void OPPROTO op_pfcmpgt(void) | |
| 1459 | +{ | |
| 1460 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1461 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1462 | + d->MMX_L(0) = float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status) ? -1 : 0; | |
| 1463 | + d->MMX_L(1) = float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status) ? -1 : 0; | |
| 1464 | +} | |
| 1465 | + | |
| 1466 | +void OPPROTO op_pfmax(void) | |
| 1467 | +{ | |
| 1468 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1469 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1470 | + if (float32_lt(d->MMX_S(0), s->MMX_S(0), &env->mmx_status)) | |
| 1471 | + d->MMX_S(0) = s->MMX_S(0); | |
| 1472 | + if (float32_lt(d->MMX_S(1), s->MMX_S(1), &env->mmx_status)) | |
| 1473 | + d->MMX_S(1) = s->MMX_S(1); | |
| 1474 | +} | |
| 1475 | + | |
| 1476 | +void OPPROTO op_pfmin(void) | |
| 1477 | +{ | |
| 1478 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1479 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1480 | + if (float32_lt(s->MMX_S(0), d->MMX_S(0), &env->mmx_status)) | |
| 1481 | + d->MMX_S(0) = s->MMX_S(0); | |
| 1482 | + if (float32_lt(s->MMX_S(1), d->MMX_S(1), &env->mmx_status)) | |
| 1483 | + d->MMX_S(1) = s->MMX_S(1); | |
| 1484 | +} | |
| 1485 | + | |
| 1486 | +void OPPROTO op_pfmul(void) | |
| 1487 | +{ | |
| 1488 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1489 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1490 | + d->MMX_S(0) = float32_mul(d->MMX_S(0), s->MMX_S(0), &env->mmx_status); | |
| 1491 | + d->MMX_S(1) = float32_mul(d->MMX_S(1), s->MMX_S(1), &env->mmx_status); | |
| 1492 | +} | |
| 1493 | + | |
| 1494 | +void OPPROTO op_pfnacc(void) | |
| 1495 | +{ | |
| 1496 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1497 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1498 | + MMXReg r; | |
| 1499 | + r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); | |
| 1500 | + r.MMX_S(1) = float32_sub(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); | |
| 1501 | + *d = r; | |
| 1502 | +} | |
| 1503 | + | |
| 1504 | +void OPPROTO op_pfpnacc(void) | |
| 1505 | +{ | |
| 1506 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1507 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1508 | + MMXReg r; | |
| 1509 | + r.MMX_S(0) = float32_sub(d->MMX_S(0), d->MMX_S(1), &env->mmx_status); | |
| 1510 | + r.MMX_S(1) = float32_add(s->MMX_S(0), s->MMX_S(1), &env->mmx_status); | |
| 1511 | + *d = r; | |
| 1512 | +} | |
| 1513 | + | |
| 1514 | +void OPPROTO op_pfrcp(void) | |
| 1515 | +{ | |
| 1516 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1517 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1518 | + d->MMX_S(0) = approx_rcp(s->MMX_S(0)); | |
| 1519 | + d->MMX_S(1) = d->MMX_S(0); | |
| 1520 | +} | |
| 1521 | + | |
| 1522 | +void OPPROTO op_pfrsqrt(void) | |
| 1523 | +{ | |
| 1524 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1525 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1526 | + d->MMX_L(1) = s->MMX_L(0) & 0x7fffffff; | |
| 1527 | + d->MMX_S(1) = approx_rsqrt(d->MMX_S(1)); | |
| 1528 | + d->MMX_L(1) |= s->MMX_L(0) & 0x80000000; | |
| 1529 | + d->MMX_L(0) = d->MMX_L(1); | |
| 1530 | +} | |
| 1531 | + | |
| 1532 | +void OPPROTO op_pfsub(void) | |
| 1533 | +{ | |
| 1534 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1535 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1536 | + d->MMX_S(0) = float32_sub(d->MMX_S(0), s->MMX_S(0), &env->mmx_status); | |
| 1537 | + d->MMX_S(1) = float32_sub(d->MMX_S(1), s->MMX_S(1), &env->mmx_status); | |
| 1538 | +} | |
| 1539 | + | |
| 1540 | +void OPPROTO op_pfsubr(void) | |
| 1541 | +{ | |
| 1542 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1543 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1544 | + d->MMX_S(0) = float32_sub(s->MMX_S(0), d->MMX_S(0), &env->mmx_status); | |
| 1545 | + d->MMX_S(1) = float32_sub(s->MMX_S(1), d->MMX_S(1), &env->mmx_status); | |
| 1546 | +} | |
| 1547 | + | |
| 1548 | +void OPPROTO op_pswapd(void) | |
| 1549 | +{ | |
| 1550 | + MMXReg *d = (MMXReg *)((char *)env + PARAM1); | |
| 1551 | + MMXReg *s = (MMXReg *)((char *)env + PARAM2); | |
| 1552 | + MMXReg r; | |
| 1553 | + r.MMX_L(0) = s->MMX_L(1); | |
| 1554 | + r.MMX_L(1) = s->MMX_L(0); | |
| 1555 | + *d = r; | |
| 1556 | +} | |
| 1557 | +#endif | |
| 1558 | + | |
| 1386 | 1559 | #undef SHIFT |
| 1387 | 1560 | #undef XMM_ONLY |
| 1388 | 1561 | #undef Reg | ... | ... |
target-i386/translate.c
| ... | ... | @@ -2408,12 +2408,16 @@ static GenOpFunc1 *gen_sto_env_A0[3] = { |
| 2408 | 2408 | }; |
| 2409 | 2409 | |
| 2410 | 2410 | #define SSE_SPECIAL ((GenOpFunc2 *)1) |
| 2411 | +#define SSE_DUMMY ((GenOpFunc2 *)2) | |
| 2411 | 2412 | |
| 2412 | 2413 | #define MMX_OP2(x) { gen_op_ ## x ## _mmx, gen_op_ ## x ## _xmm } |
| 2413 | 2414 | #define SSE_FOP(x) { gen_op_ ## x ## ps, gen_op_ ## x ## pd, \ |
| 2414 | 2415 | gen_op_ ## x ## ss, gen_op_ ## x ## sd, } |
| 2415 | 2416 | |
| 2416 | 2417 | static GenOpFunc2 *sse_op_table1[256][4] = { |
| 2418 | + /* 3DNow! extensions */ | |
| 2419 | + [0x0e] = { SSE_DUMMY }, /* femms */ | |
| 2420 | + [0x0f] = { SSE_DUMMY }, /* pf... */ | |
| 2417 | 2421 | /* pure SSE operations */ |
| 2418 | 2422 | [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ |
| 2419 | 2423 | [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */ |
| ... | ... | @@ -2480,7 +2484,7 @@ static GenOpFunc2 *sse_op_table1[256][4] = { |
| 2480 | 2484 | [0x74] = MMX_OP2(pcmpeqb), |
| 2481 | 2485 | [0x75] = MMX_OP2(pcmpeqw), |
| 2482 | 2486 | [0x76] = MMX_OP2(pcmpeql), |
| 2483 | - [0x77] = { SSE_SPECIAL }, /* emms */ | |
| 2487 | + [0x77] = { SSE_DUMMY }, /* emms */ | |
| 2484 | 2488 | [0x7c] = { NULL, gen_op_haddpd, NULL, gen_op_haddps }, |
| 2485 | 2489 | [0x7d] = { NULL, gen_op_hsubpd, NULL, gen_op_hsubps }, |
| 2486 | 2490 | [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */ |
| ... | ... | @@ -2577,6 +2581,33 @@ static GenOpFunc2 *sse_op_table4[8][4] = { |
| 2577 | 2581 | SSE_FOP(cmpord), |
| 2578 | 2582 | }; |
| 2579 | 2583 | |
| 2584 | +static GenOpFunc2 *sse_op_table5[256] = { | |
| 2585 | + [0x0c] = gen_op_pi2fw, | |
| 2586 | + [0x0d] = gen_op_pi2fd, | |
| 2587 | + [0x1c] = gen_op_pf2iw, | |
| 2588 | + [0x1d] = gen_op_pf2id, | |
| 2589 | + [0x8a] = gen_op_pfnacc, | |
| 2590 | + [0x8e] = gen_op_pfpnacc, | |
| 2591 | + [0x90] = gen_op_pfcmpge, | |
| 2592 | + [0x94] = gen_op_pfmin, | |
| 2593 | + [0x96] = gen_op_pfrcp, | |
| 2594 | + [0x97] = gen_op_pfrsqrt, | |
| 2595 | + [0x9a] = gen_op_pfsub, | |
| 2596 | + [0x9e] = gen_op_pfadd, | |
| 2597 | + [0xa0] = gen_op_pfcmpgt, | |
| 2598 | + [0xa4] = gen_op_pfmax, | |
| 2599 | + [0xa6] = gen_op_movq, /* pfrcpit1; no need to actually increase precision */ | |
| 2600 | + [0xa7] = gen_op_movq, /* pfrsqit1 */ | |
| 2601 | + [0xaa] = gen_op_pfsubr, | |
| 2602 | + [0xae] = gen_op_pfacc, | |
| 2603 | + [0xb0] = gen_op_pfcmpeq, | |
| 2604 | + [0xb4] = gen_op_pfmul, | |
| 2605 | + [0xb6] = gen_op_movq, /* pfrcpit2 */ | |
| 2606 | + [0xb7] = gen_op_pmulhrw_mmx, | |
| 2607 | + [0xbb] = gen_op_pswapd, | |
| 2608 | + [0xbf] = gen_op_pavgb_mmx /* pavgusb */ | |
| 2609 | +}; | |
| 2610 | + | |
| 2580 | 2611 | static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) |
| 2581 | 2612 | { |
| 2582 | 2613 | int b1, op1_offset, op2_offset, is_xmm, val, ot; |
| ... | ... | @@ -2596,7 +2627,7 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) |
| 2596 | 2627 | sse_op2 = sse_op_table1[b][b1]; |
| 2597 | 2628 | if (!sse_op2) |
| 2598 | 2629 | goto illegal_op; |
| 2599 | - if (b <= 0x5f || b == 0xc6 || b == 0xc2) { | |
| 2630 | + if ((b <= 0x5f && b >= 0x10) || b == 0xc6 || b == 0xc2) { | |
| 2600 | 2631 | is_xmm = 1; |
| 2601 | 2632 | } else { |
| 2602 | 2633 | if (b1 == 0) { |
| ... | ... | @@ -2618,8 +2649,8 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) |
| 2618 | 2649 | } |
| 2619 | 2650 | if (is_xmm && !(s->flags & HF_OSFXSR_MASK)) |
| 2620 | 2651 | goto illegal_op; |
| 2621 | - if (b == 0x77) { | |
| 2622 | - /* emms */ | |
| 2652 | + if (b == 0x77 || b == 0x0e) { | |
| 2653 | + /* emms or femms */ | |
| 2623 | 2654 | gen_op_emms(); |
| 2624 | 2655 | return; |
| 2625 | 2656 | } |
| ... | ... | @@ -3151,6 +3182,13 @@ static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r) |
| 3151 | 3182 | } |
| 3152 | 3183 | } |
| 3153 | 3184 | switch(b) { |
| 3185 | + case 0x0f: /* 3DNow! data insns */ | |
| 3186 | + val = ldub_code(s->pc++); | |
| 3187 | + sse_op2 = sse_op_table5[val]; | |
| 3188 | + if (!sse_op2) | |
| 3189 | + goto illegal_op; | |
| 3190 | + sse_op2(op1_offset, op2_offset); | |
| 3191 | + break; | |
| 3154 | 3192 | case 0x70: /* pshufx insn */ |
| 3155 | 3193 | case 0xc6: /* pshufx insn */ |
| 3156 | 3194 | val = ldub_code(s->pc++); |
| ... | ... | @@ -6148,7 +6186,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
| 6148 | 6186 | gen_eob(s); |
| 6149 | 6187 | } |
| 6150 | 6188 | break; |
| 6151 | - /* MMX/SSE/SSE2/PNI support */ | |
| 6189 | + /* MMX/3DNow!/SSE/SSE2/SSE3 support */ | |
| 6152 | 6190 | case 0x1c3: /* MOVNTI reg, mem */ |
| 6153 | 6191 | if (!(s->cpuid_features & CPUID_SSE2)) |
| 6154 | 6192 | goto illegal_op; |
| ... | ... | @@ -6214,6 +6252,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
| 6214 | 6252 | case 7: /* sfence / clflush */ |
| 6215 | 6253 | if ((modrm & 0xc7) == 0xc0) { |
| 6216 | 6254 | /* sfence */ |
| 6255 | + /* XXX: also check for cpuid_ext2_features & CPUID_EXT2_EMMX */ | |
| 6217 | 6256 | if (!(s->cpuid_features & CPUID_SSE)) |
| 6218 | 6257 | goto illegal_op; |
| 6219 | 6258 | } else { |
| ... | ... | @@ -6227,8 +6266,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
| 6227 | 6266 | goto illegal_op; |
| 6228 | 6267 | } |
| 6229 | 6268 | break; |
| 6230 | - case 0x10d: /* prefetch */ | |
| 6269 | + case 0x10d: /* 3DNow! prefetch(w) */ | |
| 6231 | 6270 | modrm = ldub_code(s->pc++); |
| 6271 | + mod = (modrm >> 6) & 3; | |
| 6272 | + if (mod == 3) | |
| 6273 | + goto illegal_op; | |
| 6232 | 6274 | gen_lea_modrm(s, modrm, ®_addr, &offset_addr); |
| 6233 | 6275 | /* ignore for now */ |
| 6234 | 6276 | break; |
| ... | ... | @@ -6245,6 +6287,9 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start) |
| 6245 | 6287 | gen_op_rsm(); |
| 6246 | 6288 | gen_eob(s); |
| 6247 | 6289 | break; |
| 6290 | + case 0x10e ... 0x10f: | |
| 6291 | + /* 3DNow! instructions, ignore prefixes */ | |
| 6292 | + s->prefix &= ~(PREFIX_REPZ | PREFIX_REPNZ | PREFIX_DATA); | |
| 6248 | 6293 | case 0x110 ... 0x117: |
| 6249 | 6294 | case 0x128 ... 0x12f: |
| 6250 | 6295 | case 0x150 ... 0x177: | ... | ... |