- Timestamp:
- Mar 12, 2022 1:42:58 PM (3 years ago)
- File:
-
- 1 edited
-
trunk/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp
r94192 r94195 2625 2625 * - OF is set according to the last sub-shift on AMD 3990X. 2626 2626 * - 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. 2627 2633 */ 2628 2634 #define EMIT_SHLD(a_cBitsWidth, a_uType, a_Suffix, a_fIntelFlags) \ … … 2676 2682 { \ 2677 2683 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; \ 2679 2687 uint16_t const uResult = (uint16_t)((uTmp << cShift) >> 32); \ 2680 2688 *puDst = uResult; \ … … 2682 2690 /* CALC EFLAGS: */ \ 2683 2691 uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \ 2692 AssertCompile(X86_EFL_CF_BIT == 0); \ 2684 2693 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. */ \ 2686 2697 fEfl |= X86_EFL_GET_OF_16(uDst ^ (uDst << 1)); \ 2698 } \ 2687 2699 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. */ \ 2689 2702 if (cShift < 16) \ 2703 { \ 2704 fEfl |= (uDst >> (16 - cShift)) & X86_EFL_CF; \ 2690 2705 fEfl |= X86_EFL_GET_OF_16((uDst << (cShift - 1)) ^ uResult); \ 2706 } \ 2691 2707 else \ 2692 2708 fEfl |= X86_EFL_GET_OF_16((uDst << (cShift - 1)) ^ 0); \ 2693 2709 fEfl |= X86_EFL_AF; \ 2694 2710 } \ 2695 AssertCompile(X86_EFL_CF_BIT == 0); \2696 fEfl |= (uDst >> (16 - cShift)) & X86_EFL_CF; /* CF = last bit shifted out */ \2697 2711 fEfl |= g_afParity[uResult & 0xff]; \ 2698 2712 fEfl |= X86_EFL_CALC_SF(uResult, 16); \ … … 2719 2733 * - OF is set according to the last sub-shift on AMD 3990X. 2720 2734 * - 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. 2721 2741 */ 2722 2742 #define EMIT_SHRD(a_cBitsWidth, a_uType, a_Suffix, a_fIntelFlags) \ … … 2771 2791 { \ 2772 2792 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); \ 2774 2796 uint16_t const uResult = (uint16_t)(uTmp >> cShift); \ 2775 2797 *puDst = uResult; \ … … 2777 2799 uint32_t fEfl = *pfEFlags & ~X86_EFL_STATUS_BITS; \ 2778 2800 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; \2781 2801 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; \ 2782 2805 /* Intel 6700K & 10980XE: Set according to the first shift. AF always cleared. */ \ 2783 2806 fEfl |= X86_EFL_GET_OF_16(uDst ^ (uSrc << 15)); \ 2807 } \ 2784 2808 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. */ \ 2786 2813 if (cShift > 1) /* Set according to last shift. */ \ 2787 2814 fEfl |= X86_EFL_GET_OF_16((uint16_t)(uTmp >> (cShift - 1)) ^ uResult); \
Note:
See TracChangeset
for help on using the changeset viewer.

