diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj index f238a8c12e..d81664fa89 100644 --- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj +++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj @@ -2925,6 +2925,10 @@ RelativePath="..\..\x86\ix86\ix86_fpu.cpp" > + + diff --git a/pcsx2/x86/ix86/ix86.cpp b/pcsx2/x86/ix86/ix86.cpp index c1aed679ea..ec41c81e50 100644 --- a/pcsx2/x86/ix86/ix86.cpp +++ b/pcsx2/x86/ix86/ix86.cpp @@ -74,7 +74,7 @@ const x86IndexerTypeExplicit<1> ptr8; // ------------------------------------------------------------------------ template< int OperandSize > const iRegister iRegister::Empty; -const x86IndexReg x86IndexReg::Empty; +const x86IndexReg x86IndexReg::Empty; const iRegister32 eax( 0 ), ebx( 3 ), @@ -89,10 +89,12 @@ const iRegister16 bp( 5 ), sp( 4 ); const iRegister8 - al( 0 ), cl( 1 ), + al( 0 ), dl( 2 ), bl( 3 ), ah( 4 ), ch( 5 ), dh( 6 ), bh( 7 ); + +const iRegisterCL cl; namespace Internal { @@ -250,8 +252,11 @@ const Group2ImplAll iSHL; const Group2ImplAll iSHR; const Group2ImplAll iSAR; -const MovExtendImplAll iMOVSX; const MovExtendImplAll iMOVZX; +const MovExtendImplAll iMOVSX; + +const Internal::DwordShiftImplAll iSHLD; +const Internal::DwordShiftImplAll iSHRD; const CMovImplGeneric iCMOV; @@ -641,6 +646,150 @@ void iMOV( const iRegister8& to, u8 imm, bool preserve_flags ) MOV8::Emit( to, imm ); } +////////////////////////////////////////////////////////////////////////////////////////// +// DIV/MUL/IDIV/IMUL instructions (Implemented!) + +// F6 is r8, F7 is r32. +// MUL is 4, DIV is 6. + +enum MulDivType +{ + MDT_Mul = 4, + MDT_iMul = 5, + MDT_Div = 6, + MDT_iDiv = 7 +}; + +// ------------------------------------------------------------------------ +// EAX form emitter for Mul/Div/iMUL/iDIV +// +template< int OperandSize > +static __forceinline void EmitMulDiv_OneRegForm( MulDivType InstType, const iRegister& from ) +{ + if( OperandSize == 2 ) iWrite( 0x66 ); + iWrite( (OperandSize == 1) ? 0xf6 : 0xf7 ); + ModRM( ModRm_Direct, InstType, from.Id ); +} + +static __forceinline void EmitMulDiv_OneRegForm( MulDivType InstType, const ModSibSized& sibsrc ) +{ + if( sibsrc.OperandSize == 2 ) iWrite( 0x66 ); + iWrite( (sibsrc.OperandSize == 1) ? 0xf6 : 0xf7 ); + EmitSibMagic( InstType, sibsrc ); +} + +////////////////////////////////////////////////////////////////////////////////////////// +// All ioMul forms are valid for 16 and 32 bit register operands only! + +template< typename ImmType > +class iMulImpl +{ +public: + static const uint OperandSize = sizeof(ImmType); + +protected: + static void prefix16() { if( OperandSize == 2 ) iWrite( 0x66 ); } + +public: + // ------------------------------------------------------------------------ + static __forceinline void Emit( const iRegister& to, const iRegister& from ) + { + prefix16(); + write16( 0xaf0f ); + ModRM( ModRm_Direct, to.Id, from.Id ); + } + + // ------------------------------------------------------------------------ + static __forceinline void Emit( const iRegister& to, const void* src ) + { + prefix16(); + write16( 0xaf0f ); + iWriteDisp( to.Id, src ); + } + + // ------------------------------------------------------------------------ + static __forceinline void Emit( const iRegister& to, const ModSibBase& src ) + { + prefix16(); + write16( 0xaf0f ); + EmitSibMagic( to.Id, src ); + } + + // ------------------------------------------------------------------------ + static __forceinline void Emit( const iRegister& to, const iRegister& from, ImmType imm ) + { + prefix16(); + write16( is_s8( imm ) ? 0x6b : 0x69 ); + ModRM( ModRm_Direct, to.Id, from.Id ); + if( is_s8( imm ) ) + write8( imm ); + else + iWrite( imm ); + } + + // ------------------------------------------------------------------------ + static __forceinline void Emit( const iRegister& to, const void* src, ImmType imm ) + { + prefix16(); + write16( is_s8( imm ) ? 0x6b : 0x69 ); + iWriteDisp( to.Id, src ); + if( is_s8( imm ) ) + write8( imm ); + else + iWrite( imm ); + } + + // ------------------------------------------------------------------------ + static __forceinline void Emit( const iRegister& to, const ModSibBase& src, ImmType imm ) + { + prefix16(); + write16( is_s8( imm ) ? 0x6b : 0x69 ); + EmitSibMagic( to.Id, src ); + if( is_s8( imm ) ) + write8( imm ); + else + iWrite( imm ); + } +}; + +namespace Internal +{ + typedef iMulImpl iMUL32; + typedef iMulImpl iMUL16; +} + +__forceinline void iUMUL( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); } +__forceinline void iUMUL( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); } +__forceinline void iUMUL( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); } +__noinline void iUMUL( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_Mul, from ); } + +__forceinline void iUDIV( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); } +__forceinline void iUDIV( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); } +__forceinline void iUDIV( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); } +__noinline void iUDIV( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_Div, from ); } + +__forceinline void iSDIV( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); } +__forceinline void iSDIV( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); } +__forceinline void iSDIV( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); } +__noinline void iSDIV( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_iDiv, from ); } + +__forceinline void iSMUL( const iRegister32& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } +__forceinline void iSMUL( const iRegister32& to, const iRegister32& from ) { iMUL32::Emit( to, from ); } +__forceinline void iSMUL( const iRegister32& to, const void* src ) { iMUL32::Emit( to, src ); } +__forceinline void iSMUL( const iRegister32& to, const iRegister32& from, s32 imm ) { iMUL32::Emit( to, from, imm ); } +__noinline void iSMUL( const iRegister32& to, const ModSibBase& src ) { iMUL32::Emit( to, src ); } +__noinline void iSMUL( const iRegister32& to, const ModSibBase& from, s32 imm ) { iMUL32::Emit( to, from, imm ); } + +__forceinline void iSMUL( const iRegister16& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } +__forceinline void iSMUL( const iRegister16& to, const iRegister16& from ) { iMUL16::Emit( to, from ); } +__forceinline void iSMUL( const iRegister16& to, const void* src ) { iMUL16::Emit( to, src ); } +__forceinline void iSMUL( const iRegister16& to, const iRegister16& from, s16 imm ) { iMUL16::Emit( to, from, imm ); } +__noinline void iSMUL( const iRegister16& to, const ModSibBase& src ) { iMUL16::Emit( to, src ); } +__noinline void iSMUL( const iRegister16& to, const ModSibBase& from, s16 imm ) { iMUL16::Emit( to, from, imm ); } + +__forceinline void iSMUL( const iRegister8& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } +__noinline void iSMUL( const ModSibSized& from ) { EmitMulDiv_OneRegForm( MDT_iMul, from ); } + ////////////////////////////////////////////////////////////////////////////////////////// // Push / Pop Emitters diff --git a/pcsx2/x86/ix86/ix86_impl_group2.h b/pcsx2/x86/ix86/ix86_impl_group2.h index 23cb8c78a3..dd551713d1 100644 --- a/pcsx2/x86/ix86/ix86_impl_group2.h +++ b/pcsx2/x86/ix86/ix86_impl_group2.h @@ -52,10 +52,8 @@ protected: static void prefix16() { if( OperandSize == 2 ) iWrite( 0x66 ); } public: - static __emitinline void Emit( const iRegister& to, const iRegister8& from ) + static __emitinline void Emit( const iRegister& to ) { - jASSUME( from == cl ); // cl is the only valid shift register. (turn this into a compile time check?) - prefix16(); iWrite( Is8BitOperand() ? 0xd2 : 0xd3 ); ModRM( 3, InstType, to.Id ); @@ -80,13 +78,11 @@ public: } } - static __emitinline void Emit( const ModSibStrict& sibdest, const iRegister8& from ) + static __emitinline void Emit( const ModSibStrict& sibdest ) { - jASSUME( from == cl ); // cl is the only valid shift register. (turn this into a compile time check?) - prefix16(); iWrite( Is8BitOperand() ? 0xd2 : 0xd3 ); - EmitSibMagic( from.Id, sibdest ); + EmitSibMagic( InstType, sibdest ); } static __emitinline void Emit( const ModSibStrict& sibdest, u8 imm ) @@ -130,20 +126,20 @@ protected: public: // ---------- 32 Bit Interface ----------- - __forceinline void operator()( const iRegister32& to, const iRegister8& from ) const { m_32::Emit( to, from ); } - __noinline void operator()( const ModSibStrict<4>& sibdest, const iRegister8& from ) const { m_32::Emit( sibdest, from ); } + __forceinline void operator()( const iRegister32& to, __unused const iRegisterCL& from ) const{ m_32::Emit( to ); } + __noinline void operator()( const ModSibStrict<4>& sibdest, __unused const iRegisterCL& from ) const{ m_32::Emit( sibdest ); } __noinline void operator()( const ModSibStrict<4>& sibdest, u8 imm ) const { m_32::Emit( sibdest, imm ); } void operator()( const iRegister32& to, u8 imm ) const { m_32::Emit( to, imm ); } // ---------- 16 Bit Interface ----------- - __forceinline void operator()( const iRegister16& to, const iRegister8& from ) const { m_16::Emit( to, from ); } - __noinline void operator()( const ModSibStrict<2>& sibdest, const iRegister8& from ) const { m_16::Emit( sibdest, from ); } + __forceinline void operator()( const iRegister16& to, __unused const iRegisterCL& from ) const{ m_16::Emit( to ); } + __noinline void operator()( const ModSibStrict<2>& sibdest, __unused const iRegisterCL& from ) const{ m_16::Emit( sibdest ); } __noinline void operator()( const ModSibStrict<2>& sibdest, u8 imm ) const { m_16::Emit( sibdest, imm ); } void operator()( const iRegister16& to, u8 imm ) const { m_16::Emit( to, imm ); } // ---------- 8 Bit Interface ----------- - __forceinline void operator()( const iRegister8& to, const iRegister8& from ) const { m_8::Emit( to, from ); } - __noinline void operator()( const ModSibStrict<1>& sibdest, const iRegister8& from ) const { m_8::Emit( sibdest, from ); } + __forceinline void operator()( const iRegister8& to, __unused const iRegisterCL& from ) const{ m_8::Emit( to ); } + __noinline void operator()( const ModSibStrict<1>& sibdest, __unused const iRegisterCL& from ) const{ m_8::Emit( sibdest ); } __noinline void operator()( const ModSibStrict<1>& sibdest, u8 imm ) const { m_8::Emit( sibdest, imm ); } void operator()( const iRegister8& to, u8 imm ) const { m_8::Emit( to, imm ); } diff --git a/pcsx2/x86/ix86/ix86_instructions.h b/pcsx2/x86/ix86/ix86_instructions.h index 3b8b885a11..533c2dbd57 100644 --- a/pcsx2/x86/ix86/ix86_instructions.h +++ b/pcsx2/x86/ix86/ix86_instructions.h @@ -82,6 +82,42 @@ namespace x86Emitter // NOP 1-byte __forceinline void iNOP() { write8(0x90); } + + ////////////////////////////////////////////////////////////////////////////////////////// + // MUL / DIV instructions + + extern void iUMUL( const iRegister32& from ); + extern void iUMUL( const iRegister16& from ); + extern void iUMUL( const iRegister8& from ); + extern void iUMUL( const ModSibSized& from ); + + extern void iUDIV( const iRegister32& from ); + extern void iUDIV( const iRegister16& from ); + extern void iUDIV( const iRegister8& from ); + extern void iUDIV( const ModSibSized& from ); + + extern void iSDIV( const iRegister32& from ); + extern void iSDIV( const iRegister16& from ); + extern void iSDIV( const iRegister8& from ); + extern void iSDIV( const ModSibSized& from ); + + extern void iSMUL( const iRegister32& from ); + extern void iSMUL( const iRegister32& to, const iRegister32& from ); + extern void iSMUL( const iRegister32& to, const void* src ); + extern void iSMUL( const iRegister32& to, const iRegister32& from, s32 imm ); + extern void iSMUL( const iRegister32& to, const ModSibBase& src ); + extern void iSMUL( const iRegister32& to, const ModSibBase& src, s32 imm ); + + extern void iSMUL( const iRegister16& from ); + extern void iSMUL( const iRegister16& to, const iRegister16& from ); + extern void iSMUL( const iRegister16& to, const void* src ); + extern void iSMUL( const iRegister16& to, const iRegister16& from, s16 imm ); + extern void iSMUL( const iRegister16& to, const ModSibBase& src ); + extern void iSMUL( const iRegister16& to, const ModSibBase& src, s16 imm ); + + extern void iSMUL( const iRegister8& from ); + extern void iSMUL( const ModSibSized& from ); + ////////////////////////////////////////////////////////////////////////////////////////// // MOV instructions! diff --git a/pcsx2/x86/ix86/ix86_legacy.cpp b/pcsx2/x86/ix86/ix86_legacy.cpp index d0fd220455..3f12a7f818 100644 --- a/pcsx2/x86/ix86/ix86_legacy.cpp +++ b/pcsx2/x86/ix86/ix86_legacy.cpp @@ -117,9 +117,9 @@ DEFINE_OPCODE_LEGACY( MOV ) // ------------------------------------------------------------------------ #define DEFINE_LEGACY_MOVEXTEND( form, destbits, srcbits ) \ - emitterT void MOV##form##destbits##R##srcbits##toR( x86IntRegType to, x86IntRegType from ) { iMOV##form##( iRegister##destbits( to ), iRegister##srcbits( from ) ); } \ - emitterT void MOV##form##destbits##Rm##srcbits##toR( x86IntRegType to, x86IntRegType from, int offset ) { iMOV##form##( iRegister##destbits( to ), ptr##srcbits[x86IndexReg( from ) + offset] ); } \ - emitterT void MOV##form##destbits##M##srcbits##toR( x86IntRegType to, u32 from ) { iMOV##form##( iRegister##destbits( to ), ptr##srcbits[from] ); } + emitterT void MOV##form##destbits##R##srcbits##toR( x86IntRegType to, x86IntRegType from ) { iMOV##form( iRegister##destbits( to ), iRegister##srcbits( from ) ); } \ + emitterT void MOV##form##destbits##Rm##srcbits##toR( x86IntRegType to, x86IntRegType from, int offset ) { iMOV##form( iRegister##destbits( to ), ptr##srcbits[x86IndexReg( from ) + offset] ); } \ + emitterT void MOV##form##destbits##M##srcbits##toR( x86IntRegType to, u32 from ) { iMOV##form( iRegister##destbits( to ), ptr##srcbits[from] ); } DEFINE_LEGACY_MOVEXTEND( SX, 32, 16 ) DEFINE_LEGACY_MOVEXTEND( ZX, 32, 16 ) @@ -164,7 +164,53 @@ emitterT void CMOVE32RtoR( x86IntRegType to, x86IntRegType from ) iCMOVE( iRegister32(to), iRegister32(from) ); } +// shld imm8 to r32 +emitterT void SHLD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) +{ + iSHLD( iRegister32(to), iRegister32(from), shift ); +} +// shrd imm8 to r32 +emitterT void SHRD32ItoR( x86IntRegType to, x86IntRegType from, u8 shift ) +{ + iSHRD( iRegister32(to), iRegister32(from), shift ); +} + +emitterT void LEA32RtoR(x86IntRegType to, x86IntRegType from, s32 offset) +{ + iLEA( iRegister32( to ), ptr[x86IndexReg(from)+offset] ); +} + +emitterT void LEA32RRtoR(x86IntRegType to, x86IntRegType from0, x86IntRegType from1) +{ + iLEA( iRegister32( to ), ptr[x86IndexReg(from0)+x86IndexReg(from1)] ); +} + +// Don't inline recursive functions +emitterT void LEA32RStoR(x86IntRegType to, x86IntRegType from, u32 scale) +{ + iLEA( iRegister32( to ), ptr[x86IndexReg(from)*(1< iRegister16; typedef iRegister<1> iRegister8; - extern const iRegister32 eax; - extern const iRegister32 ebx; - extern const iRegister32 ecx; - extern const iRegister32 edx; - extern const iRegister32 esi; - extern const iRegister32 edi; - extern const iRegister32 ebp; - extern const iRegister32 esp; + class iRegisterCL : public iRegister8 + { + public: + iRegisterCL(): iRegister8( 1 ) {} + }; - extern const iRegister16 ax; - extern const iRegister16 bx; - extern const iRegister16 cx; - extern const iRegister16 dx; - extern const iRegister16 si; - extern const iRegister16 di; - extern const iRegister16 bp; - extern const iRegister16 sp; + extern const iRegister32 + eax, ebx, ecx, edx, + esi, edi, ebp, esp; - extern const iRegister8 al; - extern const iRegister8 cl; - extern const iRegister8 dl; - extern const iRegister8 bl; - extern const iRegister8 ah; - extern const iRegister8 ch; - extern const iRegister8 dh; - extern const iRegister8 bh; + extern const iRegister16 + ax, bx, cx, dx, + si, di, bp, sp; + + extern const iRegister8 + al, dl, bl, + ah, ch, dh, bh; + + extern const iRegisterCL cl; // I'm special! ////////////////////////////////////////////////////////////////////////////////////////// // Use 32 bit registers as out index register (for ModSib memory address calculations) @@ -346,6 +340,13 @@ namespace x86Emitter __forceinline iAddressInfo operator-( s32 imm ) const { return iAddressInfo( *this ).Add( -imm ); } }; + enum OperandSizeType + { + OpSize_8 = 1, + OpSize_16 = 2, + OpSize_32 = 4, + }; + ////////////////////////////////////////////////////////////////////////////////////////// // ModSib - Internal low-level representation of the ModRM/SIB information. // @@ -387,26 +388,64 @@ namespace x86Emitter }; ////////////////////////////////////////////////////////////////////////////////////////// - // Strictly-typed version of ModSibBase, which is used to apply operand size information - // to ImmToMem operations. // - template< int OperandSize > - class ModSibStrict : public ModSibBase + class ModSibSized : public ModSibBase { public: - __forceinline explicit ModSibStrict( const iAddressInfo& src ) : ModSibBase( src ) {} - __forceinline explicit ModSibStrict( s32 disp ) : ModSibBase( disp ) {} - __forceinline ModSibStrict( x86IndexReg base, x86IndexReg index, int scale=0, s32 displacement=0 ) : - ModSibBase( base, index, scale, displacement ) {} + int OperandSize; - __forceinline ModSibStrict& Add( s32 imm ) + ModSibSized( int opsize, const iAddressInfo& src ) : + ModSibBase( src ), + OperandSize( opsize ) + { + jASSUME( OperandSize == 1 || OperandSize == 2 || OperandSize == 4 ); + } + + ModSibSized( int opsize, s32 disp ) : + ModSibBase( disp ), + OperandSize( opsize ) + { + jASSUME( OperandSize == 1 || OperandSize == 2 || OperandSize == 4 ); + } + + ModSibSized( int opsize, x86IndexReg base, x86IndexReg index, int scale=0, s32 displacement=0 ) : + ModSibBase( base, index, scale, displacement ), + OperandSize( opsize ) + { + jASSUME( OperandSize == 1 || OperandSize == 2 || OperandSize == 4 ); + } + + __forceinline ModSibSized& Add( s32 imm ) { Displacement += imm; return *this; } - __forceinline ModSibStrict operator+( const s32 imm ) const { return ModSibStrict( *this ).Add( imm ); } - __forceinline ModSibStrict operator-( const s32 imm ) const { return ModSibStrict( *this ).Add( -imm ); } + __forceinline ModSibSized operator+( const s32 imm ) const { return ModSibSized( *this ).Add( imm ); } + __forceinline ModSibSized operator-( const s32 imm ) const { return ModSibSized( *this ).Add( -imm ); } + }; + + ////////////////////////////////////////////////////////////////////////////////////////// + // Strictly-typed version of ModSibBase, which is used to apply operand size information + // to ImmToMem operations. + // + template< int OpSize > + class ModSibStrict : public ModSibSized + { + public: + __forceinline explicit ModSibStrict( const iAddressInfo& src ) : ModSibSized( OpSize, src ) {} + __forceinline explicit ModSibStrict( s32 disp ) : ModSibSized( OpSize, disp ) {} + __forceinline ModSibStrict( x86IndexReg base, x86IndexReg index, int scale=0, s32 displacement=0 ) : + ModSibSized( OpSize, base, index, scale, displacement ) {} + + __forceinline ModSibStrict& Add( s32 imm ) + { + Displacement += imm; + return *this; + } + + __forceinline ModSibStrict operator+( const s32 imm ) const { return ModSibStrict( *this ).Add( imm ); } + __forceinline ModSibStrict operator-( const s32 imm ) const { return ModSibStrict( *this ).Add( -imm ); } }; ////////////////////////////////////////////////////////////////////////////////////////// @@ -605,7 +644,8 @@ namespace x86Emitter #include "ix86_impl_group1.h" #include "ix86_impl_group2.h" - #include "ix86_impl_movs.h" + #include "ix86_impl_movs.h" // cmov and movsx/zx + #include "ix86_impl_dwshift.h" // dowubleword shifts! // if the immediate is zero, we can replace the instruction, or ignore it // entirely, depending on the instruction being issued. That's what we do here. @@ -675,8 +715,11 @@ namespace x86Emitter extern const Internal::Group2ImplAll iSHR; extern const Internal::Group2ImplAll iSAR; + extern const Internal::MovExtendImplAll iMOVZX; extern const Internal::MovExtendImplAll iMOVSX; - extern const Internal::MovExtendImplAll iMOVZX; + + extern const Internal::DwordShiftImplAll iSHLD; + extern const Internal::DwordShiftImplAll iSHRD; extern const Internal::CMovImplGeneric iCMOV;