VirtualBox

Changeset 94195 in vbox for trunk


Ignore:
Timestamp:
Mar 12, 2022 1:42:58 PM (3 years ago)
Author:
vboxsync
Message:

VMM/IEM: Adjusted double shifts C code to match intel behaviour. bugref:9898

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp

    r94192 r94195  
    26252625 *  - OF is set according to the last sub-shift on AMD 3990X.
    26262626 *  - ZF, SF and PF are calculated according to the result by both vendors.
     2627 *
     2628 * For 16-bit shifts the count mask isn't 15, but 31, and the CPU will
     2629 * pick either the source register or the destination register for input bits
     2630 * when going beyond 16.  According to https://www.sandpile.org/x86/flags.htm
     2631 * intel has changed behaviour here several times.  We implement what current
     2632 * skylake based does for now, we can extend this later as needed.
    26272633 */
    26282634#define EMIT_SHLD(a_cBitsWidth, a_uType, a_Suffix, a_fIntelFlags) \
     
    26762682    { \
    26772683        uint16_t const uDst    = *puDst; \
    2678         uint64_t const uTmp    = ((uint64_t)uDst << 32) | ((uint32_t)uSrc << 16) | uSrc; \
     2684        uint64_t const uTmp    = a_fIntelFlags \
     2685                               ? ((uint64_t)uDst << 32) | ((uint32_t)uSrc << 16) | uDst \
     2686                               : ((uint64_t)uDst << 32) | ((uint32_t)uSrc << 16) | uSrc; \
    26792687        uint16_t const uResult = (uint16_t)((uTmp << cShift) >> 32); \
    26802688        *puDst = uResult; \
     
    26822690        /* CALC EFLAGS: */ \
    26832691        uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \
     2692        AssertCompile(X86_EFL_CF_BIT == 0); \
    26842693        if (a_fIntelFlags) \
    2685             /* Intel 6700K & 10980XE: Set according to the first shift. AF always cleared. */ \
     2694        { \
     2695            fEfl |= (uTmp >> (48 - cShift)) & X86_EFL_CF; /* CF = last bit shifted out of the combined operand */ \
     2696            /* Intel 6700K & 10980XE: OF is et according to the first shift. AF always cleared. */ \
    26862697            fEfl |= X86_EFL_GET_OF_16(uDst ^ (uDst << 1));  \
     2698        } \
    26872699        else \
    2688         {   /* AMD 3990X: Set according to last shift, with some weirdness. AF always set. */ \
     2700        { \
     2701            /* AMD 3990X: OF is set according to last shift, with some weirdness. AF always set. CF = last bit shifted out of uDst. */ \
    26892702            if (cShift < 16) \
     2703            { \
     2704                fEfl |= (uDst >> (16 - cShift)) & X86_EFL_CF;  \
    26902705                fEfl |= X86_EFL_GET_OF_16((uDst << (cShift - 1)) ^ uResult); \
     2706            } \
    26912707            else \
    26922708                fEfl |= X86_EFL_GET_OF_16((uDst << (cShift - 1)) ^ 0); \
    26932709            fEfl |= X86_EFL_AF; \
    26942710        } \
    2695         AssertCompile(X86_EFL_CF_BIT == 0); \
    2696         fEfl |= (uDst >> (16 - cShift)) & X86_EFL_CF; /* CF = last bit shifted out */ \
    26972711        fEfl |= g_afParity[uResult & 0xff]; \
    26982712        fEfl |= X86_EFL_CALC_SF(uResult, 16); \
     
    27192733 *  - OF is set according to the last sub-shift on AMD 3990X.
    27202734 *  - ZF, SF and PF are calculated according to the result by both vendors.
     2735 *
     2736 * For 16-bit shifts the count mask isn't 15, but 31, and the CPU will
     2737 * pick either the source register or the destination register for input bits
     2738 * when going beyond 16.  According to https://www.sandpile.org/x86/flags.htm
     2739 * intel has changed behaviour here several times.  We implement what current
     2740 * skylake based does for now, we can extend this later as needed.
    27212741 */
    27222742#define EMIT_SHRD(a_cBitsWidth, a_uType, a_Suffix, a_fIntelFlags) \
     
    27712791    { \
    27722792        uint16_t const uDst    = *puDst; \
    2773         uint64_t const uTmp    = uDst | ((uint32_t)uSrc << 16) | ((uint64_t)uSrc << 32); \
     2793        uint64_t const uTmp    = a_fIntelFlags \
     2794                               ? uDst | ((uint32_t)uSrc << 16) | ((uint64_t)uDst << 32) \
     2795                               : uDst | ((uint32_t)uSrc << 16) | ((uint64_t)uSrc << 32); \
    27742796        uint16_t const uResult = (uint16_t)(uTmp >> cShift); \
    27752797        *puDst = uResult; \
     
    27772799        uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \
    27782800        AssertCompile(X86_EFL_CF_BIT == 0); \
    2779         /* AMD 3990X: CF flag seems to be last bit shifted out of uDst, not the combined uSrc:uSrc:uDst operand. */ \
    2780         fEfl |= (uDst >> (cShift - 1)) & X86_EFL_CF; \
    27812801        if (a_fIntelFlags) \
     2802        { \
     2803            /* Intel 10980XE: The CF is the last shifted out of the combined uTmp operand. */ \
     2804            fEfl |= (uTmp >> (cShift - 1)) & X86_EFL_CF; \
    27822805            /* Intel 6700K & 10980XE: Set according to the first shift. AF always cleared. */ \
    27832806            fEfl |= X86_EFL_GET_OF_16(uDst ^ (uSrc << 15)); \
     2807        } \
    27842808        else \
    2785         {   /* AMD 3990X: Set according to last shift. AF always set. */ \
     2809        { \
     2810            /* AMD 3990X: CF flag seems to be last bit shifted out of uDst, not the combined uSrc:uSrc:uDst operand. */ \
     2811            fEfl |= (uDst >> (cShift - 1)) & X86_EFL_CF; \
     2812            /* AMD 3990X: Set according to last shift. AF always set. */ \
    27862813            if (cShift > 1) /* Set according to last shift. */ \
    27872814                fEfl |= X86_EFL_GET_OF_16((uint16_t)(uTmp >> (cShift - 1)) ^ uResult); \
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette