mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-26 04:22:07 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			612 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			612 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * Copyright (c) 2021, Leon Albrecht <leon2002.la@gmail.com>
 | |
|  *
 | |
|  * SPDX-License-Identifier: BSD-2-Clause
 | |
|  */
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include "Report.h"
 | |
| #include <AK/Concepts.h>
 | |
| #include <AK/SIMD.h>
 | |
| #include <LibX86/Instruction.h>
 | |
| #include <LibX86/Interpreter.h>
 | |
| 
 | |
| #include <math.h>
 | |
| #include <string.h>
 | |
| 
 | |
| namespace UserspaceEmulator {
 | |
| using namespace AK::SIMD;
 | |
| class Emulator;
 | |
| class SoftCPU;
 | |
| 
 | |
| union MMX {
 | |
|     u64 raw;
 | |
|     c8x8 v8;
 | |
|     i16x4 v16;
 | |
|     i32x2 v32;
 | |
|     i16x4 v16u;
 | |
|     i32x2 v32u;
 | |
| };
 | |
| static_assert(sizeof(MMX) == sizeof(u64));
 | |
| 
 | |
| class SoftFPU final {
 | |
| public:
 | |
|     SoftFPU(Emulator& emulator, SoftCPU& cpu)
 | |
|         : m_emulator(emulator)
 | |
|         , m_cpu(cpu)
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE bool c0() const { return m_fpu_c0; }
 | |
|     ALWAYS_INLINE bool c1() const { return m_fpu_c1; }
 | |
|     ALWAYS_INLINE bool c2() const { return m_fpu_c2; }
 | |
|     ALWAYS_INLINE bool c3() const { return m_fpu_c3; }
 | |
| 
 | |
|     ALWAYS_INLINE void set_c0(bool val) { m_fpu_c0 = val; }
 | |
|     ALWAYS_INLINE void set_c1(bool val) { m_fpu_c1 = val; }
 | |
|     ALWAYS_INLINE void set_c2(bool val) { m_fpu_c2 = val; }
 | |
|     ALWAYS_INLINE void set_c3(bool val) { m_fpu_c3 = val; }
 | |
| 
 | |
|     long double fpu_get(u8 index) const;
 | |
| 
 | |
|     void fpu_push(long double value);
 | |
|     long double fpu_pop();
 | |
|     void fpu_set_absolute(u8 index, long double value);
 | |
|     void fpu_set(u8 index, long double value);
 | |
| 
 | |
|     MMX mmx_get(u8 index) const;
 | |
|     void mmx_set(u8 index, MMX value);
 | |
| 
 | |
| private:
 | |
|     friend class SoftCPU;
 | |
| 
 | |
|     Emulator& m_emulator;
 | |
|     SoftCPU& m_cpu;
 | |
| 
 | |
|     enum class FPU_Exception : u8 {
 | |
|         InvalidOperation,
 | |
|         DenormalizedOperand,
 | |
|         ZeroDivide,
 | |
|         Overflow,
 | |
|         Underflow,
 | |
|         Precision,
 | |
|         StackFault,
 | |
|     };
 | |
| 
 | |
|     enum class FPU_Tag : u8 {
 | |
|         Valid = 0b00,
 | |
|         Zero = 0b01,
 | |
|         Special = 0b10,
 | |
|         Empty = 0b11
 | |
|     };
 | |
| 
 | |
|     enum class RoundingMode : u8 {
 | |
|         NEAREST = 0b00,
 | |
|         DOWN = 0b01,
 | |
|         UP = 0b10,
 | |
|         TRUNK = 0b11
 | |
|     };
 | |
| 
 | |
|     void fpu_dump_env()
 | |
|     {
 | |
|         reportln("Exceptions: #I:{} #D:{} #O:{} #D:{} #U:{} #P:{} #SF:{} Summary:{}",
 | |
|             m_fpu_error_invalid,
 | |
|             m_fpu_error_denorm,
 | |
|             m_fpu_error_zero_div,
 | |
|             m_fpu_error_overflow,
 | |
|             m_fpu_error_underflow,
 | |
|             m_fpu_error_precision,
 | |
|             m_fpu_error_stackfault,
 | |
|             m_fpu_error_summary);
 | |
|         reportln("Masks: #I:{} #D:{} #O:{} #D:{} #U:{} #P:{}",
 | |
|             m_fpu_mask_invalid,
 | |
|             m_fpu_mask_denorm,
 | |
|             m_fpu_mask_zero_div,
 | |
|             m_fpu_mask_overflow,
 | |
|             m_fpu_mask_underflow,
 | |
|             m_fpu_mask_precision);
 | |
|         reportln("C0:{} C1:{} C2:{} C3:{}", c0(), c1(), c2(), c3());
 | |
|         reportln("fpu-stacktop: {}", m_fpu_stack_top);
 | |
|         reportln("fpu-stack /w stacktop (real):");
 | |
|         for (u8 i = 0; i < 8; ++i) {
 | |
|             reportln("\t{} ({}): fp {} ({}), mmx (:x016)", i, (u8)((m_fpu_stack_top + i) % 8), m_storage[(m_fpu_stack_top + i) % 8].fp, fpu_is_set(i) ? "set" : "free", m_storage[(m_fpu_stack_top + i) % 8].mmx.raw);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     String fpu_exception_string(FPU_Exception ex)
 | |
|     {
 | |
|         switch (ex) {
 | |
|         case FPU_Exception::StackFault:
 | |
|             return "Stackfault";
 | |
|         case FPU_Exception::InvalidOperation:
 | |
|             return "Invalid Operation";
 | |
|         case FPU_Exception::DenormalizedOperand:
 | |
|             return "Denormalized Operant";
 | |
|         case FPU_Exception::ZeroDivide:
 | |
|             return "Divide by Zero";
 | |
|         case FPU_Exception::Overflow:
 | |
|             return "Overflow";
 | |
|         case FPU_Exception::Underflow:
 | |
|             return "Underflow";
 | |
|         case FPU_Exception::Precision:
 | |
|             return "Precision";
 | |
|         }
 | |
|         VERIFY_NOT_REACHED();
 | |
|     }
 | |
| 
 | |
|     // FIXME: Technically we should check for exceptions after each insn, too,
 | |
|     //        this might be important for FLDENV, but otherwise it should
 | |
|     //        be fine this way
 | |
|     void fpu_set_exception(FPU_Exception ex);
 | |
| 
 | |
|     ALWAYS_INLINE void fpu_set_stack_overflow()
 | |
|     {
 | |
|         reportln("Stack Overflow");
 | |
|         set_c1(1);
 | |
|         fpu_set_exception(FPU_Exception::StackFault);
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE void fpu_set_stack_underflow()
 | |
|     {
 | |
|         reportln("Stack Underflow");
 | |
|         set_c1(0);
 | |
|         fpu_set_exception(FPU_Exception::StackFault);
 | |
|     }
 | |
| 
 | |
|     constexpr FPU_Tag fpu_get_tag_absolute(u8 index) const
 | |
|     {
 | |
|         switch (index) {
 | |
|         case 0:
 | |
|             return FPU_Tag(m_fpu_status_0);
 | |
|         case 1:
 | |
|             return FPU_Tag(m_fpu_status_1);
 | |
|         case 2:
 | |
|             return FPU_Tag(m_fpu_status_2);
 | |
|         case 3:
 | |
|             return FPU_Tag(m_fpu_status_3);
 | |
|         case 4:
 | |
|             return FPU_Tag(m_fpu_status_4);
 | |
|         case 5:
 | |
|             return FPU_Tag(m_fpu_status_5);
 | |
|         case 6:
 | |
|             return FPU_Tag(m_fpu_status_6);
 | |
|         case 7:
 | |
|             return FPU_Tag(m_fpu_status_7);
 | |
|         default:
 | |
|             VERIFY_NOT_REACHED();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     constexpr FPU_Tag fpu_get_tag(u8 index) const
 | |
|     {
 | |
|         VERIFY(index < 8);
 | |
|         return fpu_get_tag_absolute((m_fpu_stack_top + index) % 8);
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE void fpu_set_tag_absolute(u8 index, FPU_Tag tag)
 | |
|     {
 | |
|         switch (index) {
 | |
|         case 0:
 | |
|             m_fpu_status_0 = (u8)tag;
 | |
|             break;
 | |
|         case 1:
 | |
|             m_fpu_status_1 = (u8)tag;
 | |
|             break;
 | |
|         case 2:
 | |
|             m_fpu_status_2 = (u8)tag;
 | |
|             break;
 | |
|         case 3:
 | |
|             m_fpu_status_3 = (u8)tag;
 | |
|             break;
 | |
|         case 4:
 | |
|             m_fpu_status_4 = (u8)tag;
 | |
|             break;
 | |
|         case 5:
 | |
|             m_fpu_status_5 = (u8)tag;
 | |
|             break;
 | |
|         case 6:
 | |
|             m_fpu_status_6 = (u8)tag;
 | |
|             break;
 | |
|         case 7:
 | |
|             m_fpu_status_7 = (u8)tag;
 | |
|             break;
 | |
|         default:
 | |
|             VERIFY_NOT_REACHED();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE void fpu_set_tag(u8 index, FPU_Tag tag)
 | |
|     {
 | |
|         VERIFY(index < 8);
 | |
|         fpu_set_tag_absolute((m_fpu_stack_top + index) % 8, tag);
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE void set_tag_from_value_absolute(u8 index, long double val)
 | |
|     {
 | |
|         switch (fpclassify(val)) {
 | |
|         case FP_ZERO:
 | |
|             fpu_set_tag_absolute(index, FPU_Tag::Zero);
 | |
|             break;
 | |
|         case FP_NAN:
 | |
|         case FP_INFINITE:
 | |
|         case FP_SUBNORMAL:
 | |
|             fpu_set_tag_absolute(index, FPU_Tag::Special);
 | |
|             break;
 | |
|         case FP_NORMAL:
 | |
|             fpu_set_tag_absolute(index, FPU_Tag::Valid);
 | |
|             break;
 | |
|         default:
 | |
|             VERIFY_NOT_REACHED();
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE void set_tag_from_value(u8 index, long double val)
 | |
|     {
 | |
|         set_tag_from_value_absolute((m_fpu_stack_top + index) % 8, val);
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE bool fpu_isnan(u8 index) const
 | |
|     {
 | |
|         return isnan(fpu_get(index));
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE bool fpu_is_set(u8 index) const
 | |
|     {
 | |
|         return fpu_get_tag_absolute((m_fpu_stack_top + index) % 8) != FPU_Tag::Empty;
 | |
|     }
 | |
| 
 | |
|     ALWAYS_INLINE RoundingMode fpu_get_round_mode() const
 | |
|     {
 | |
|         return RoundingMode(m_fpu_round_mode);
 | |
|     }
 | |
| 
 | |
|     template<Arithmetic T>
 | |
|     T fpu_round(long double) const;
 | |
|     template<Arithmetic T>
 | |
|     T fpu_round_checked(long double);
 | |
| 
 | |
|     template<FloatingPoint T>
 | |
|     T fpu_convert(long double) const;
 | |
|     template<FloatingPoint T>
 | |
|     T fpu_convert_checked(long double);
 | |
| 
 | |
|     ALWAYS_INLINE void fpu_set_unordered()
 | |
|     {
 | |
|         set_c0(1);
 | |
|         set_c2(1);
 | |
|         set_c3(1);
 | |
|     }
 | |
|     void warn_if_mmx_absolute(u8 index) const;
 | |
|     void warn_if_fpu_absolute(u8 index) const;
 | |
|     void warn_if_fpu_not_set_absolute(u8 index) const;
 | |
| 
 | |
|     void mmx_common() { m_fpu_tw = 0; }
 | |
| 
 | |
|     bool m_reg_is_mmx[8] { false };
 | |
| 
 | |
|     union {
 | |
|         long double fp;
 | |
|         struct {
 | |
|             MMX mmx;
 | |
|             Conditional<sizeof(long double) == 16,
 | |
|                 u64,
 | |
|                 Conditional<sizeof(long double) == 12,
 | |
|                     u32,
 | |
|                     u16>>
 | |
|                 __high;
 | |
|         };
 | |
|     } m_storage[8];
 | |
| 
 | |
|     union {
 | |
|         u16 m_fpu_cw { 0x037F };
 | |
|         struct {
 | |
|             u16 m_fpu_mask_invalid : 1;
 | |
|             u16 m_fpu_mask_denorm : 1;
 | |
|             u16 m_fpu_mask_zero_div : 1;
 | |
|             u16 m_fpu_mask_overflow : 1;
 | |
|             u16 m_fpu_mask_underflow : 1;
 | |
|             u16 m_fpu_mask_precision : 1;
 | |
|             u16 : 2; // unused
 | |
|             u16 m_fpu_precission : 2;
 | |
|             u16 m_fpu_round_mode : 2;
 | |
|             u16 m_fpu_infinity_control : 1;
 | |
|             u16 : 3; // unused
 | |
|         };
 | |
|     };
 | |
| 
 | |
|     union {
 | |
|         u16 m_fpu_sw { 0 };
 | |
|         struct {
 | |
|             u16 m_fpu_error_invalid : 1;    // pre | IE -> #I (#IS, #IA)
 | |
|             u16 m_fpu_error_denorm : 1;     // pre | DE -> #D
 | |
|             u16 m_fpu_error_zero_div : 1;   // pre | ZE -> #Z
 | |
|             u16 m_fpu_error_overflow : 1;   // post| OE -> #O
 | |
|             u16 m_fpu_error_underflow : 1;  // post| UE -> #U
 | |
|             u16 m_fpu_error_precision : 1;  // post| PE -> #P
 | |
|             u16 m_fpu_error_stackfault : 1; // SF
 | |
|             u16 m_fpu_error_summary : 1;
 | |
|             u16 m_fpu_c0 : 1;
 | |
|             u16 m_fpu_c1 : 1;
 | |
|             u16 m_fpu_c2 : 1;
 | |
|             u16 m_fpu_stack_top : 3;
 | |
|             u16 m_fpu_c3 : 1;
 | |
|             u16 m_fpu_busy : 1;
 | |
|         };
 | |
|     };
 | |
| 
 | |
|     union {
 | |
|         u16 m_fpu_tw { 0xFFFF };
 | |
|         struct {
 | |
|             u16 m_fpu_status_0 : 2;
 | |
|             u16 m_fpu_status_1 : 2;
 | |
|             u16 m_fpu_status_2 : 2;
 | |
|             u16 m_fpu_status_3 : 2;
 | |
|             u16 m_fpu_status_4 : 2;
 | |
|             u16 m_fpu_status_5 : 2;
 | |
|             u16 m_fpu_status_6 : 2;
 | |
|             u16 m_fpu_status_7 : 2;
 | |
|         };
 | |
|     };
 | |
| 
 | |
|     u32 m_fpu_ip { 0 };
 | |
|     u16 m_fpu_cs { 0 };
 | |
| 
 | |
|     u32 m_fpu_dp { 0 };
 | |
|     u16 m_fpu_ds { 0 };
 | |
| 
 | |
|     u16 m_fpu_iop { 0 };
 | |
| 
 | |
|     // Instructions
 | |
| 
 | |
|     // DATA TRANSFER
 | |
|     void FLD_RM32(const X86::Instruction&);
 | |
|     void FLD_RM64(const X86::Instruction&);
 | |
|     void FLD_RM80(const X86::Instruction&);
 | |
| 
 | |
|     void FST_RM32(const X86::Instruction&);
 | |
|     void FST_RM64(const X86::Instruction&);
 | |
|     void FSTP_RM32(const X86::Instruction&);
 | |
|     void FSTP_RM64(const X86::Instruction&);
 | |
|     void FSTP_RM80(const X86::Instruction&);
 | |
| 
 | |
|     void FILD_RM32(const X86::Instruction&);
 | |
|     void FILD_RM16(const X86::Instruction&);
 | |
|     void FILD_RM64(const X86::Instruction&);
 | |
| 
 | |
|     void FIST_RM16(const X86::Instruction&);
 | |
|     void FIST_RM32(const X86::Instruction&);
 | |
|     void FISTP_RM16(const X86::Instruction&);
 | |
|     void FISTP_RM32(const X86::Instruction&);
 | |
|     void FISTP_RM64(const X86::Instruction&);
 | |
|     void FISTTP_RM16(const X86::Instruction&);
 | |
|     void FISTTP_RM32(const X86::Instruction&);
 | |
|     void FISTTP_RM64(const X86::Instruction&);
 | |
| 
 | |
|     void FBLD_M80(const X86::Instruction&);
 | |
|     void FBSTP_M80(const X86::Instruction&);
 | |
| 
 | |
|     void FXCH(const X86::Instruction&);
 | |
| 
 | |
|     void FCMOVE(const X86::Instruction&);
 | |
|     void FCMOVNE(const X86::Instruction&);
 | |
|     void FCMOVB(const X86::Instruction&);
 | |
|     void FCMOVBE(const X86::Instruction&);
 | |
|     void FCMOVNB(const X86::Instruction&);
 | |
|     void FCMOVNBE(const X86::Instruction&);
 | |
|     void FCMOVU(const X86::Instruction&);
 | |
|     void FCMOVNU(const X86::Instruction&);
 | |
| 
 | |
|     // BASIC ARITHMETIC
 | |
|     void FADD_RM32(const X86::Instruction&);
 | |
|     void FADD_RM64(const X86::Instruction&);
 | |
|     void FADDP(const X86::Instruction&);
 | |
| 
 | |
|     void FIADD_RM16(const X86::Instruction&);
 | |
|     void FIADD_RM32(const X86::Instruction&);
 | |
| 
 | |
|     void FSUB_RM32(const X86::Instruction&);
 | |
|     void FSUB_RM64(const X86::Instruction&);
 | |
|     void FSUBP(const X86::Instruction&);
 | |
|     void FSUBR_RM32(const X86::Instruction&);
 | |
|     void FSUBR_RM64(const X86::Instruction&);
 | |
|     void FSUBRP(const X86::Instruction&);
 | |
| 
 | |
|     void FISUB_RM16(const X86::Instruction&);
 | |
|     void FISUB_RM32(const X86::Instruction&);
 | |
|     void FISUBR_RM16(const X86::Instruction&);
 | |
|     void FISUBR_RM32(const X86::Instruction&);
 | |
| 
 | |
|     void FMUL_RM32(const X86::Instruction&);
 | |
|     void FMUL_RM64(const X86::Instruction&);
 | |
|     void FMULP(const X86::Instruction&);
 | |
| 
 | |
|     void FIMUL_RM16(const X86::Instruction&);
 | |
|     void FIMUL_RM32(const X86::Instruction&);
 | |
| 
 | |
|     void FDIV_RM32(const X86::Instruction&);
 | |
|     void FDIV_RM64(const X86::Instruction&);
 | |
|     void FDIVP(const X86::Instruction&);
 | |
|     void FDIVR_RM32(const X86::Instruction&);
 | |
|     void FDIVR_RM64(const X86::Instruction&);
 | |
|     void FDIVRP(const X86::Instruction&);
 | |
| 
 | |
|     void FIDIV_RM16(const X86::Instruction&);
 | |
|     void FIDIV_RM32(const X86::Instruction&);
 | |
|     void FIDIVR_RM16(const X86::Instruction&);
 | |
|     void FIDIVR_RM32(const X86::Instruction&);
 | |
| 
 | |
|     void FPREM(const X86::Instruction&);
 | |
|     void FPREM1(const X86::Instruction&);
 | |
| 
 | |
|     void FABS(const X86::Instruction&);
 | |
|     void FCHS(const X86::Instruction&);
 | |
| 
 | |
|     void FRNDINT(const X86::Instruction&);
 | |
| 
 | |
|     void FSCALE(const X86::Instruction&);
 | |
| 
 | |
|     void FSQRT(const X86::Instruction&);
 | |
| 
 | |
|     void FXTRACT(const X86::Instruction&);
 | |
| 
 | |
|     // COMPARISON
 | |
|     void FCOM_RM32(const X86::Instruction&);
 | |
|     void FCOM_RM64(const X86::Instruction&);
 | |
|     void FCOMP_RM32(const X86::Instruction&);
 | |
|     void FCOMP_RM64(const X86::Instruction&);
 | |
|     void FCOMPP(const X86::Instruction&);
 | |
|     void FCOMI(const X86::Instruction&);
 | |
|     void FCOMIP(const X86::Instruction&);
 | |
| 
 | |
|     void FUCOM(const X86::Instruction&);
 | |
|     void FUCOMP(const X86::Instruction&);
 | |
|     void FUCOMPP(const X86::Instruction&);
 | |
|     void FUCOMI(const X86::Instruction&);
 | |
|     void FUCOMIP(const X86::Instruction&);
 | |
| 
 | |
|     void FICOM_RM16(const X86::Instruction&);
 | |
|     void FICOM_RM32(const X86::Instruction&);
 | |
|     void FICOMP_RM16(const X86::Instruction&);
 | |
|     void FICOMP_RM32(const X86::Instruction&);
 | |
| 
 | |
|     void FTST(const X86::Instruction&);
 | |
|     void FXAM(const X86::Instruction&);
 | |
| 
 | |
|     // TRANSCENDENTAL
 | |
|     void FSIN(const X86::Instruction&);
 | |
|     void FCOS(const X86::Instruction&);
 | |
|     void FSINCOS(const X86::Instruction&);
 | |
|     void FPTAN(const X86::Instruction&);
 | |
|     void FPATAN(const X86::Instruction&);
 | |
| 
 | |
|     void F2XM1(const X86::Instruction&);
 | |
|     void FYL2X(const X86::Instruction&);
 | |
|     void FYL2XP1(const X86::Instruction&);
 | |
| 
 | |
|     // CONSTANT LOAD
 | |
|     void FLD1(const X86::Instruction&);
 | |
|     void FLDZ(const X86::Instruction&);
 | |
|     void FLDPI(const X86::Instruction&);
 | |
|     void FLDL2E(const X86::Instruction&);
 | |
|     void FLDLN2(const X86::Instruction&);
 | |
|     void FLDL2T(const X86::Instruction&);
 | |
|     void FLDLG2(const X86::Instruction&);
 | |
| 
 | |
|     // CONTROL
 | |
|     void FINCSTP(const X86::Instruction&);
 | |
|     void FDECSTP(const X86::Instruction&);
 | |
|     void FFREE(const X86::Instruction&);
 | |
|     void FFREEP(const X86::Instruction&); // undocumented
 | |
| 
 | |
|     // FIXME: Non N- versions?
 | |
|     void FNINIT(const X86::Instruction&);
 | |
|     void FNCLEX(const X86::Instruction&);
 | |
| 
 | |
|     void FNSTCW(const X86::Instruction&);
 | |
|     void FLDCW(const X86::Instruction&);
 | |
| 
 | |
|     void FNSTENV(const X86::Instruction&);
 | |
|     void FLDENV(const X86::Instruction&);
 | |
| 
 | |
|     void FNSAVE(const X86::Instruction&);
 | |
|     void FRSTOR(const X86::Instruction&);
 | |
| 
 | |
|     void FNSTSW(const X86::Instruction&);
 | |
|     void FNSTSW_AX(const X86::Instruction&);
 | |
| 
 | |
|     // FIXME: WAIT && FWAIT
 | |
|     void FNOP(const X86::Instruction&);
 | |
| 
 | |
|     // FPU & SIMD MANAGEMENT
 | |
|     // FIXME: FXSAVE && FXRSTOR
 | |
| 
 | |
|     // DO NOTHING?
 | |
|     // FIXME: FENI, FDISI, FSETPM
 | |
|     void FNENI(const X86::Instruction&);
 | |
|     void FNDISI(const X86::Instruction&);
 | |
|     void FNSETPM(const X86::Instruction&);
 | |
| 
 | |
|     // MMX
 | |
|     // ARITHMETIC
 | |
|     void PADDB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PADDW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PADDD_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PADDSB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PADDSW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PADDUSB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PADDUSW_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     void PSUBB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSUBW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSUBD_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSUBSB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSUBSW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSUBUSB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSUBUSW_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     void PMULHW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PMULLW_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     void PMADDWD_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     // COMPARISON
 | |
|     void PCMPEQB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PCMPEQW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PCMPEQD_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     void PCMPGTB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PCMPGTW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PCMPGTD_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     // CONVERSION
 | |
|     void PACKSSDW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PACKSSWB_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PACKUSWB_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     // UNPACK
 | |
|     void PUNPCKHBW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PUNPCKHWD_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PUNPCKHDQ_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PUNPCKLBW_mm1_mm2m32(const X86::Instruction&);
 | |
|     void PUNPCKLWD_mm1_mm2m32(const X86::Instruction&);
 | |
|     void PUNPCKLDQ_mm1_mm2m32(const X86::Instruction&);
 | |
| 
 | |
|     // LOGICAL
 | |
|     void PAND_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PANDN_mm1_mm2m64(const X86::Instruction&);
 | |
|     void POR_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PXOR_mm1_mm2m64(const X86::Instruction&);
 | |
| 
 | |
|     // SHIFT
 | |
|     void PSLLW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSLLW_mm1_imm8(const X86::Instruction&);
 | |
|     void PSLLD_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSLLD_mm1_imm8(const X86::Instruction&);
 | |
|     void PSLLQ_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSLLQ_mm1_imm8(const X86::Instruction&);
 | |
|     void PSRAW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSRAW_mm1_imm8(const X86::Instruction&);
 | |
|     void PSRAD_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSRAD_mm1_imm8(const X86::Instruction&);
 | |
|     void PSRLW_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSRLW_mm1_imm8(const X86::Instruction&);
 | |
|     void PSRLD_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSRLD_mm1_imm8(const X86::Instruction&);
 | |
|     void PSRLQ_mm1_mm2m64(const X86::Instruction&);
 | |
|     void PSRLQ_mm1_imm8(const X86::Instruction&);
 | |
| 
 | |
|     // DATA TRANSFER
 | |
|     void MOVD_mm1_rm32(const X86::Instruction&);
 | |
|     void MOVD_rm32_mm2(const X86::Instruction&);
 | |
| 
 | |
|     void MOVQ_mm1_mm2m64(const X86::Instruction&);
 | |
|     void MOVQ_mm1m64_mm2(const X86::Instruction&);
 | |
|     void MOVQ_mm1_rm64(const X86::Instruction&); // long mode
 | |
|     void MOVQ_rm64_mm2(const X86::Instruction&); // long mode
 | |
| 
 | |
|     // EMPTY MMX STATE
 | |
|     void EMMS(const X86::Instruction&);
 | |
| };
 | |
| 
 | |
| }
 | 
