diff --git a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
index 51852e0cdc..6df72ec1ea 100644
--- a/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
+++ b/pcsx2/windows/VCprojects/pcsx2_2008.vcproj
@@ -2980,6 +2980,10 @@
+
+
@@ -3004,6 +3008,10 @@
RelativePath="..\..\x86\ix86\implement\movs.h"
>
+
+
+class Group8Impl
+{
+protected:
+ static const uint OperandSize = sizeof(ImmType);
+
+ static void prefix16() { if( OperandSize == 2 ) iWrite( 0x66 ); }
+
+public:
+ Group8Impl() {} // For the love of GCC.
+
+ static __emitinline void Emit( const iRegister& bitbase, const iRegister& bitoffset )
+ {
+ prefix16();
+ iWrite( 0x0f );
+ iWrite( 0xa3 | (InstType << 2) );
+ ModRM_Direct( bitoffset.Id, bitbase.Id );
+ }
+
+ static __emitinline void Emit( void* bitbase, const iRegister& bitoffset )
+ {
+ prefix16();
+ iWrite( 0x0f );
+ iWrite( 0xa3 | (InstType << 2) );
+ iWriteDisp( bitoffset.Id, bitbase.Id );
+ }
+
+ static __emitinline void Emit( const ModSibBase& bitbase, const iRegister& bitoffset )
+ {
+ prefix16();
+ iWrite( 0x0f );
+ iWrite( 0xa3 | (InstType << 2) );
+ EmitSibMagic( bitoffset.Id, bitbase );
+ }
+
+ static __emitinline void Emit( const iRegister& bitbase, u8 immoffset )
+ {
+ prefix16();
+ iWrite( 0xba0f );
+ ModRM_Direct( InstType, bitbase.Id );
+ iWrite( immoffset );
+ }
+
+ static __emitinline void Emit( const ModSibStrict& bitbase, u8 immoffset )
+ {
+ prefix16();
+ iWrite( 0xba0f );
+ EmitSibMagic( InstType, bitbase );
+ iWrite( immoffset );
+ }
+};
+
+// -------------------------------------------------------------------
+//
+template< G8Type InstType >
+class Group8ImplAll
+{
+protected:
+ typedef Group8Impl m_32;
+ typedef Group8Impl m_16;
+
+public:
+ __forceinline void operator()( const iRegister32& bitbase, const iRegister32& bitoffset ) const { m_32::Emit( bitbase, bitoffset ); }
+ __forceinline void operator()( const iRegister16& bitbase, const iRegister16& bitoffset ) const { m_16::Emit( bitbase, bitoffset ); }
+ __forceinline void operator()( void* bitbase, const iRegister32& bitoffset ) const { m_32::Emit( bitbase, bitoffset ); }
+ __forceinline void operator()( void* bitbase, const iRegister16& bitoffset ) const { m_16::Emit( bitbase, bitoffset ); }
+ __noinline void operator()( const ModSibBase& bitbase, const iRegister32& bitoffset ) const { m_32::Emit( bitbase, bitoffset ); }
+ __noinline void operator()( const ModSibBase& bitbase, const iRegister16& bitoffset ) const { m_16::Emit( bitbase, bitoffset ); }
+
+ // Note on Imm forms : use int as the source operand since it's "reasonably inert" from a compiler
+ // perspective. (using uint tends to make the compiler try and fail to match signed immediates with
+ // one of the other overloads).
+
+ __noinline void operator()( const ModSibStrict& bitbase, u8 immoffset ) const { m_32::Emit( bitbase, immoffset ); }
+ __noinline void operator()( const ModSibStrict& bitbase, u8 immoffset ) const { m_16::Emit( bitbase, immoffset ); }
+ void operator()( const iRegister& bitbase, u8 immoffset ) const { m_32::Emit( bitbase, immoffset ); }
+ void operator()( const iRegister& bitbase, u8 immoffset ) const { m_16::Emit( bitbase, immoffset ); }
+
+ Group8ImplAll() {}
+};
diff --git a/pcsx2/x86/ix86/implement/movs.h b/pcsx2/x86/ix86/implement/movs.h
index 6b14e58702..80ff2a4cdd 100644
--- a/pcsx2/x86/ix86/implement/movs.h
+++ b/pcsx2/x86/ix86/implement/movs.h
@@ -27,10 +27,8 @@
template< typename ImmType >
class MovImpl
{
-public:
- static const uint OperandSize = sizeof(ImmType);
-
protected:
+ static const uint OperandSize = sizeof(ImmType);
static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) iWrite( 0x66 ); }
@@ -44,7 +42,7 @@ public:
prefix16();
iWrite( Is8BitOperand() ? 0x88 : 0x89 );
- ModRM( 3, from.Id, to.Id );
+ ModRM_Direct( from.Id, to.Id );
}
// ------------------------------------------------------------------------
@@ -187,14 +185,16 @@ public:
//////////////////////////////////////////////////////////////////////////////////////////
// CMOV !! [in all of it's disappointing lack-of glory]
+// Caution! This instruction can look exciting and cool, until you realize that it cannot
+// load immediate values into registers. -_-
//
-template< typename ImmType >
-class CMovImpl
+template< typename ImmType, int InstBaseVal >
+class CMovSetImpl
{
protected:
static const uint OperandSize = sizeof(ImmType);
- static bool Is8BitOperand() {return OperandSize == 1; }
+ static bool Is8BitOperand() { return OperandSize == 1; }
static void prefix16() { if( OperandSize == 2 ) iWrite( 0x66 ); }
static __forceinline void emit_base( JccComparisonType cc )
@@ -202,11 +202,11 @@ protected:
jASSUME( cc >= 0 && cc <= 0x0f );
prefix16();
write8( 0x0f );
- write8( 0x40 | cc );
+ write8( InstBaseVal | cc );
}
public:
- CMovImpl() {}
+ CMovSetImpl() {}
static __emitinline void Emit( JccComparisonType cc, const iRegister& to, const iRegister& from )
{
@@ -226,6 +226,27 @@ public:
emit_base( cc );
EmitSibMagic( to.Id, sibsrc );
}
+
+ // This form is provided for SETcc only (not available in CMOV)
+ static __emitinline void EmitSet( JccComparisonType cc, const iRegister& to )
+ {
+ emit_base( cc );
+ ModRM_Direct( 0, to.Id );
+ }
+
+ // This form is provided for SETcc only (not available in CMOV)
+ static __emitinline void EmitSet( JccComparisonType cc, const void* src )
+ {
+ emit_base( cc );
+ iWriteDisp( 0, src );
+ }
+
+ // This form is provided for SETcc only (not available in CMOV)
+ static __emitinline void EmitSet( JccComparisonType cc, const ModSibStrict& sibsrc )
+ {
+ emit_base( cc );
+ EmitSibMagic( 0, sibsrc );
+ }
};
// ------------------------------------------------------------------------
@@ -235,8 +256,8 @@ public:
class CMovImplGeneric
{
protected:
- typedef CMovImpl m_32;
- typedef CMovImpl m_16;
+ typedef CMovSetImpl m_32; // 0x40 is the cmov base instruction id
+ typedef CMovSetImpl m_16; // 0x40 is the cmov base instruction id
public:
__forceinline void operator()( JccComparisonType ccType, const iRegister32& to, const iRegister32& from ) const { m_32::Emit( ccType, to, from ); }
@@ -255,8 +276,8 @@ template< JccComparisonType ccType >
class CMovImplAll
{
protected:
- typedef CMovImpl m_32;
- typedef CMovImpl m_16;
+ typedef CMovSetImpl m_32;
+ typedef CMovSetImpl m_16;
public:
__forceinline void operator()( const iRegister32& to, const iRegister32& from ) const { m_32::Emit( ccType, to, from ); }
@@ -270,6 +291,36 @@ public:
CMovImplAll() {} // don't ask.
};
+// ------------------------------------------------------------------------
+class SetImplGeneric
+{
+protected:
+ typedef CMovSetImpl Impl; // 0x90 is the SETcc base instruction id
+
+public:
+ __forceinline void operator()( JccComparisonType cc, const iRegister8& to ) const { Impl::EmitSet( cc, to ); }
+ __forceinline void operator()( JccComparisonType cc, void* dest ) const { Impl::EmitSet( cc, dest ); }
+ __noinline void operator()( JccComparisonType cc, const ModSibStrict& dest ) const { Impl::EmitSet( cc, dest ); }
+
+ SetImplGeneric() {} // if you do, ask GCC.
+};
+
+// ------------------------------------------------------------------------
+template< JccComparisonType ccType >
+class SetImplAll
+{
+protected:
+ typedef CMovSetImpl Impl; // 0x90 is the SETcc base instruction id
+
+public:
+ __forceinline void operator()( const iRegister8& to ) const { Impl::EmitSet( ccType, to ); }
+ __forceinline void operator()( void* dest ) const { Impl::EmitSet( ccType, dest ); }
+ __noinline void operator()( const ModSibStrict& dest ) const { Impl::EmitSet( ccType, dest ); }
+
+ SetImplAll() {} // if you do, ask GCC.
+};
+
+
//////////////////////////////////////////////////////////////////////////////////////////
// Mov with sign/zero extension implementations (movsx / movzx)
//
diff --git a/pcsx2/x86/ix86/implement/test.h b/pcsx2/x86/ix86/implement/test.h
new file mode 100644
index 0000000000..c7b2fa58b2
--- /dev/null
+++ b/pcsx2/x86/ix86/implement/test.h
@@ -0,0 +1,83 @@
+/* Pcsx2 - Pc Ps2 Emulator
+ * Copyright (C) 2002-2009 Pcsx2 Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#pragma once
+
+//////////////////////////////////////////////////////////////////////////////////////////
+// MOV instruction Implementation
+
+template< typename ImmType >
+class TestImpl
+{
+protected:
+ static const uint OperandSize = sizeof(ImmType);
+ static bool Is8BitOperand() { return OperandSize == 1; }
+ static void prefix16() { if( OperandSize == 2 ) iWrite( 0x66 ); }
+
+public:
+ TestImpl() {}
+
+ // ------------------------------------------------------------------------
+ static __emitinline void Emit( const iRegister& to, const iRegister& from )
+ {
+ prefix16();
+ iWrite( Is8BitOperand() ? 0x84 : 0x85 );
+ ModRM_Direct( from.Id, to.Id );
+ }
+
+ // ------------------------------------------------------------------------
+ static __emitinline void Emit( const iRegister& to, ImmType imm )
+ {
+ prefix16();
+
+ if( to.IsAccumulator() )
+ iWrite( Is8BitOperand() ? 0xa8 : 0xa9 );
+ else
+ {
+ iWrite( Is8BitOperand() ? 0xf6 : 0xf7 );
+ ModRM_Direct( 0, to.Id );
+ }
+ iWrite( imm );
+ }
+
+ // ------------------------------------------------------------------------
+ static __emitinline void Emit( ModSibStrict dest, ImmType imm )
+ {
+ prefix16();
+ iWrite( Is8BitOperand() ? 0xf6 : 0xf7 );
+ EmitSibMagic( 0, dest );
+ iWrite( imm );
+ }
+};
+
+// -------------------------------------------------------------------
+//
+class TestImplAll
+{
+public:
+ template< typename T >
+ __forceinline void operator()( const iRegister& to, const iRegister& from ) const { TestImpl::Emit( to, from ); }
+
+ template< typename T >
+ __noinline void operator()( const ModSibStrict& sibdest, T imm ) const { TestImpl::Emit( sibdest, imm ); }
+ template< typename T >
+ void operator()( const iRegister& to, T imm ) const { TestImpl::Emit( to, imm ); }
+
+ TestImplAll() {} // Why does GCC need these?
+};
+
diff --git a/pcsx2/x86/ix86/ix86.cpp b/pcsx2/x86/ix86/ix86.cpp
index d9d9d0ecda..004ac9f4f9 100644
--- a/pcsx2/x86/ix86/ix86.cpp
+++ b/pcsx2/x86/ix86/ix86.cpp
@@ -241,6 +241,7 @@ namespace Internal
using namespace Internal;
const MovImplAll iMOV;
+const TestImplAll iTEST;
const Group1ImplAll iADD;
const Group1ImplAll iOR;
@@ -271,9 +272,15 @@ const IncDecImplAll iDEC;
const MovExtendImplAll iMOVZX;
const MovExtendImplAll iMOVSX;
-const Internal::DwordShiftImplAll iSHLD;
-const Internal::DwordShiftImplAll iSHRD;
+const DwordShiftImplAll iSHLD;
+const DwordShiftImplAll iSHRD;
+const Group8ImplAll iBT;
+const Group8ImplAll iBTR;
+const Group8ImplAll iBTS;
+const Group8ImplAll iBTC;
+
+// ------------------------------------------------------------------------
const CMovImplGeneric iCMOV;
const CMovImplAll iCMOVA;
@@ -301,6 +308,35 @@ const CMovImplAll iCMOVNS;
const CMovImplAll iCMOVPE;
const CMovImplAll iCMOVPO;
+// ------------------------------------------------------------------------
+const SetImplGeneric iSET;
+
+const SetImplAll iSETA;
+const SetImplAll iSETAE;
+const SetImplAll iSETB;
+const SetImplAll iSETBE;
+
+const SetImplAll iSETG;
+const SetImplAll iSETGE;
+const SetImplAll iSETL;
+const SetImplAll iSETLE;
+
+const SetImplAll iSETZ;
+const SetImplAll iSETE;
+const SetImplAll iSETNZ;
+const SetImplAll iSETNE;
+
+const SetImplAll iSETO;
+const SetImplAll iSETNO;
+const SetImplAll iSETC;
+const SetImplAll iSETNC;
+
+const SetImplAll iSETS;
+const SetImplAll iSETNS;
+const SetImplAll iSETPE;
+const SetImplAll iSETPO;
+
+
// ------------------------------------------------------------------------
// Assigns the current emitter buffer target address.
// This is provided instead of using x86Ptr directly, since we may in the future find
@@ -582,13 +618,13 @@ __noinline void iSMUL( const iRegister16& to, const ModSibBase& from, s16 imm )
__emitinline void iPOP( const ModSibBase& from )
{
iWrite( 0x8f );
- Internal::EmitSibMagic( 0, from );
+ EmitSibMagic( 0, from );
}
__emitinline void iPUSH( const ModSibBase& from )
{
iWrite( 0xff );
- Internal::EmitSibMagic( 6, from );
+ EmitSibMagic( 6, from );
}
diff --git a/pcsx2/x86/ix86/ix86_instructions.h b/pcsx2/x86/ix86/ix86_instructions.h
index d625b6a7c5..9a59620ce6 100644
--- a/pcsx2/x86/ix86/ix86_instructions.h
+++ b/pcsx2/x86/ix86/ix86_instructions.h
@@ -119,7 +119,6 @@ namespace x86Emitter
typedef iForwardJump iForwardJump8;
typedef iForwardJump iForwardJump32;
-
DEFINE_FORWARD_JUMP( JA, Jcc_Above );
DEFINE_FORWARD_JUMP( JB, Jcc_Below );
diff --git a/pcsx2/x86/ix86/ix86_legacy.cpp b/pcsx2/x86/ix86/ix86_legacy.cpp
index 79f442a190..0ecac70f31 100644
--- a/pcsx2/x86/ix86/ix86_legacy.cpp
+++ b/pcsx2/x86/ix86/ix86_legacy.cpp
@@ -145,6 +145,20 @@ DEFINE_LEGACY_MOVEXTEND( ZX, 32, 8 )
DEFINE_LEGACY_MOVEXTEND( SX, 16, 8 )
DEFINE_LEGACY_MOVEXTEND( ZX, 16, 8 )
+emitterT void TEST32ItoR( x86IntRegType to, u32 from ) { iTEST( iRegister32(to), from ); }
+emitterT void TEST32ItoM( uptr to, u32 from ) { iTEST( ptr32[to], from ); }
+emitterT void TEST32RtoR( x86IntRegType to, x86IntRegType from ) { iTEST( iRegister32(to), iRegister32(from) ); }
+emitterT void TEST32ItoRm( x86IntRegType to, u32 from ) { iTEST( ptr32[x86IndexReg(to)], from ); }
+
+emitterT void TEST16ItoR( x86IntRegType to, u16 from ) { iTEST( iRegister16(to), from ); }
+emitterT void TEST16ItoM( uptr to, u16 from ) { iTEST( ptr16[to], from ); }
+emitterT void TEST16RtoR( x86IntRegType to, x86IntRegType from ) { iTEST( iRegister16(to), iRegister16(from) ); }
+emitterT void TEST16ItoRm( x86IntRegType to, u16 from ) { iTEST( ptr16[x86IndexReg(to)], from ); }
+
+emitterT void TEST8ItoR( x86IntRegType to, u8 from ) { iTEST( iRegister8(to), from ); }
+emitterT void TEST8ItoM( uptr to, u8 from ) { iTEST( ptr8[to], from ); }
+emitterT void TEST8RtoR( x86IntRegType to, x86IntRegType from ) { iTEST( iRegister8(to), iRegister8(from) ); }
+emitterT void TEST8ItoRm( x86IntRegType to, u8 from ) { iTEST( ptr8[x86IndexReg(to)], from ); }
// mov r32 to [r32<(to), from );
@@ -251,6 +263,53 @@ emitterT void LEA16RStoR(x86IntRegType to, x86IntRegType from, u32 scale)
iLEA( iRegister16( to ), ptr[x86IndexReg(from)*(1< iROL;
extern const Internal::Group2ImplAll iROR;
@@ -672,6 +675,12 @@ namespace x86Emitter
extern const Internal::DwordShiftImplAll iSHLD;
extern const Internal::DwordShiftImplAll iSHRD;
+ extern const Internal::Group8ImplAll iBT;
+ extern const Internal::Group8ImplAll iBTR;
+ extern const Internal::Group8ImplAll iBTS;
+ extern const Internal::Group8ImplAll iBTC;
+
+ // ------------------------------------------------------------------------
extern const Internal::CMovImplGeneric iCMOV;
extern const Internal::CMovImplAll iCMOVA;
@@ -698,6 +707,35 @@ namespace x86Emitter
extern const Internal::CMovImplAll iCMOVNS;
extern const Internal::CMovImplAll iCMOVPE;
extern const Internal::CMovImplAll iCMOVPO;
+
+ // ------------------------------------------------------------------------
+ extern const Internal::SetImplGeneric iSET;
+
+ extern const Internal::SetImplAll iSETA;
+ extern const Internal::SetImplAll iSETAE;
+ extern const Internal::SetImplAll iSETB;
+ extern const Internal::SetImplAll iSETBE;
+
+ extern const Internal::SetImplAll iSETG;
+ extern const Internal::SetImplAll iSETGE;
+ extern const Internal::SetImplAll iSETL;
+ extern const Internal::SetImplAll iSETLE;
+
+ extern const Internal::SetImplAll iSETZ;
+ extern const Internal::SetImplAll iSETE;
+ extern const Internal::SetImplAll iSETNZ;
+ extern const Internal::SetImplAll iSETNE;
+
+ extern const Internal::SetImplAll iSETO;
+ extern const Internal::SetImplAll iSETNO;
+ extern const Internal::SetImplAll iSETC;
+ extern const Internal::SetImplAll iSETNC;
+
+ extern const Internal::SetImplAll iSETS;
+ extern const Internal::SetImplAll iSETNS;
+ extern const Internal::SetImplAll iSETPE;
+ extern const Internal::SetImplAll iSETPO;
+
}