Permalink
Cannot retrieve contributors at this time
| /* PCSX2 - PS2 Emulator for PCs | |
| * Copyright (C) 2002-2010 PCSX2 Dev Team | |
| * | |
| * PCSX2 is free software: you can redistribute it and/or modify it under the terms | |
| * of the GNU Lesser General Public License as published by the Free Software Found- | |
| * ation, either version 3 of the License, or (at your option) any later version. | |
| * | |
| * PCSX2 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 PCSX2. | |
| * If not, see <http://www.gnu.org/licenses/>. | |
| */ | |
| /* | |
| * ix86 core v0.9.1 | |
| * | |
| * Original Authors (v0.6.2 and prior): | |
| * linuzappz <linuzappz@pcsx.net> | |
| * alexey silinov | |
| * goldfinger | |
| * zerofrog(@gmail.com) | |
| * | |
| * Authors of v0.9.1: | |
| * Jake.Stine(@gmail.com) | |
| * cottonvibes(@gmail.com) | |
| * sudonim(1@gmail.com) | |
| */ | |
| #include "PrecompiledHeader.h" | |
| #include "internal.h" | |
| #include "implement/helpers.h" | |
| namespace x86Emitter | |
| { | |
| void _xMovRtoR(const xRegisterInt &to, const xRegisterInt &from) | |
| { | |
| pxAssert(to.GetOperandSize() == from.GetOperandSize()); | |
| if (to == from) | |
| return; // ignore redundant MOVs. | |
| xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? x86_Opcode_MOV_Eb_Gb : x86_Opcode_MOV_Ev_Gv, from, to); | |
| } | |
| void xImpl_Mov::operator()(const xRegisterInt &to, const xRegisterInt &from) const | |
| { | |
| // FIXME WTF? | |
| _xMovRtoR(to, from); | |
| } | |
| void xImpl_Mov::operator()(const xIndirectVoid &dest, const xRegisterInt &from) const | |
| { | |
| // mov eax has a special from when writing directly to a DISP32 address | |
| // (sans any register index/base registers). | |
| #ifndef __M_X86_64 | |
| // Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr | |
| if (from.IsAccumulator() && dest.Index.IsEmpty() && dest.Base.IsEmpty()) { | |
| xOpAccWrite(from.GetPrefix16(), from.Is8BitOp() ? 0xa2 : 0xa3, from, dest); | |
| xWrite32(dest.Displacement); | |
| } else | |
| #endif | |
| { | |
| xOpWrite(from.GetPrefix16(), from.Is8BitOp() ? 0x88 : 0x89, from, dest); | |
| } | |
| } | |
| void xImpl_Mov::operator()(const xRegisterInt &to, const xIndirectVoid &src) const | |
| { | |
| // mov eax has a special from when reading directly from a DISP32 address | |
| // (sans any register index/base registers). | |
| #ifndef __M_X86_64 | |
| // Note: On x86-64 this is an immediate 64-bit address, which is larger than the equivalent rip offset instr | |
| if (to.IsAccumulator() && src.Index.IsEmpty() && src.Base.IsEmpty()) { | |
| xOpAccWrite(to.GetPrefix16(), to.Is8BitOp() ? 0xa0 : 0xa1, to, src); | |
| xWrite32(src.Displacement); | |
| } else | |
| #endif | |
| { | |
| xOpWrite(to.GetPrefix16(), to.Is8BitOp() ? 0x8a : 0x8b, to, src); | |
| } | |
| } | |
| void xImpl_Mov::operator()(const xIndirect64orLess &dest, sptr imm) const | |
| { | |
| switch (dest.GetOperandSize()) { | |
| case 1: | |
| pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!"); | |
| break; | |
| case 2: | |
| pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!"); | |
| break; | |
| case 4: | |
| pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!"); | |
| break; | |
| case 8: | |
| pxAssertMsg(imm == (s32)imm, "Immediate won't fit in immediate slot, go through a register!"); | |
| break; | |
| default: | |
| pxAssertMsg(0, "Bad indirect size!"); | |
| } | |
| xOpWrite(dest.GetPrefix16(), dest.Is8BitOp() ? 0xc6 : 0xc7, 0, dest, dest.GetImmSize()); | |
| dest.xWriteImm(imm); | |
| } | |
| // preserve_flags - set to true to disable optimizations which could alter the state of | |
| // the flags (namely replacing mov reg,0 with xor). | |
| void xImpl_Mov::operator()(const xRegisterInt &to, sptr imm, bool preserve_flags) const | |
| { | |
| switch (to.GetOperandSize()) { | |
| case 1: | |
| pxAssertMsg(imm == (s8)imm || imm == (u8)imm, "Immediate won't fit!"); | |
| break; | |
| case 2: | |
| pxAssertMsg(imm == (s16)imm || imm == (u16)imm, "Immediate won't fit!"); | |
| break; | |
| case 4: | |
| pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit!"); | |
| break; | |
| case 8: | |
| pxAssertMsg(imm == (s32)imm || imm == (u32)imm, "Immediate won't fit in immediate slot, use mov64 or lea!"); | |
| break; | |
| default: | |
| pxAssertMsg(0, "Bad indirect size!"); | |
| } | |
| const xRegisterInt& to_ = to.GetNonWide(); | |
| if (!preserve_flags && (imm == 0)) { | |
| _g1_EmitOp(G1Type_XOR, to_, to_); | |
| } else if (imm == (u32)imm || !to.IsWide()) { | |
| // Note: MOV does not have (reg16/32,imm8) forms. | |
| u8 opcode = (to_.Is8BitOp() ? 0xb0 : 0xb8) | to_.Id; | |
| xOpAccWrite(to_.GetPrefix16(), opcode, 0, to_); | |
| to_.xWriteImm(imm); | |
| } else { | |
| xOpWrite(to.GetPrefix16(), 0xc7, 0, to); | |
| to.xWriteImm(imm); | |
| } | |
| } | |
| const xImpl_Mov xMOV; | |
| #ifdef __M_X86_64 | |
| void xImpl_MovImm64::operator()(const xRegister64& to, s64 imm, bool preserve_flags) const | |
| { | |
| if (imm == (u32)imm || imm == (s32)imm) { | |
| xMOV(to, imm, preserve_flags); | |
| } else { | |
| u8 opcode = 0xb8 | to.Id; | |
| xOpAccWrite(to.GetPrefix16(), opcode, 0, to); | |
| xWrite64(imm); | |
| } | |
| } | |
| const xImpl_MovImm64 xMOV64; | |
| #endif | |
| // -------------------------------------------------------------------------------------- | |
| // CMOVcc | |
| // -------------------------------------------------------------------------------------- | |
| #define ccSane() pxAssertDev(ccType >= 0 && ccType <= 0x0f, "Invalid comparison type specifier.") | |
| // Macro useful for trapping unwanted use of EBP. | |
| //#define EbpAssert() pxAssert( to != ebp ) | |
| #define EbpAssert() | |
| void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xRegister16or32or64 &from) const | |
| { | |
| pxAssert(to->GetOperandSize() == from->GetOperandSize()); | |
| ccSane(); | |
| xOpWrite0F(to->GetPrefix16(), x86_Opcode_INC_eAX | ccType, to, from); | |
| } | |
| void xImpl_CMov::operator()(const xRegister16or32or64 &to, const xIndirectVoid &sibsrc) const | |
| { | |
| ccSane(); | |
| xOpWrite0F(to->GetPrefix16(), x86_Opcode_INC_eAX | ccType, to, sibsrc); | |
| } | |
| //void xImpl_CMov::operator()( const xDirectOrIndirect32& to, const xDirectOrIndirect32& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); } | |
| //void xImpl_CMov::operator()( const xDirectOrIndirect16& to, const xDirectOrIndirect16& from ) const { ccSane(); _DoI_helpermess( *this, to, from ); } | |
| void xImpl_Set::operator()(const xRegister8 &to) const | |
| { | |
| ccSane(); | |
| xOpWrite0F(x86_Opcode_NOP | ccType, 0, to); | |
| } | |
| void xImpl_Set::operator()(const xIndirect8 &dest) const | |
| { | |
| ccSane(); | |
| xOpWrite0F(x86_Opcode_NOP | ccType, 0, dest); | |
| } | |
| //void xImpl_Set::operator()( const xDirectOrIndirect8& dest ) const { ccSane(); _DoI_helpermess( *this, dest ); } | |
| void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xRegister8 &from) const | |
| { | |
| EbpAssert(); | |
| xOpWrite0F( | |
| (to->GetOperandSize() == 2) ? x86_Opcode_OPSIZE : 0, | |
| SignExtend ? x86_Opcode_MOV_eSI_Iv : x86_Opcode_MOV_DH_Ib, | |
| to, from); | |
| } | |
| void xImpl_MovExtend::operator()(const xRegister16or32or64 &to, const xIndirect8 &sibsrc) const | |
| { | |
| EbpAssert(); | |
| xOpWrite0F( | |
| (to->GetOperandSize() == 2) ? x86_Opcode_OPSIZE : 0, | |
| SignExtend ? x86_Opcode_MOV_eSI_Iv : x86_Opcode_MOV_DH_Ib, | |
| to, sibsrc); | |
| } | |
| void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xRegister16 &from) const | |
| { | |
| EbpAssert(); | |
| xOpWrite0F(SignExtend ? x86_Opcode_MOV_eDI_Iv : x86_Opcode_MOV_BH_Ib, to, from); | |
| } | |
| void xImpl_MovExtend::operator()(const xRegister32or64 &to, const xIndirect16 &sibsrc) const | |
| { | |
| EbpAssert(); | |
| xOpWrite0F(SignExtend ? x86_Opcode_MOV_eDI_Iv : x86_Opcode_MOV_BH_Ib, to, sibsrc); | |
| } | |
| #if 0 | |
| void xImpl_MovExtend::operator()( const xRegister32& to, const xDirectOrIndirect16& src ) const | |
| { | |
| EbpAssert(); | |
| _DoI_helpermess( *this, to, src ); | |
| } | |
| void xImpl_MovExtend::operator()( const xRegister16or32& to, const xDirectOrIndirect8& src ) const | |
| { | |
| EbpAssert(); | |
| _DoI_helpermess( *this, to, src ); | |
| } | |
| #endif | |
| const xImpl_MovExtend xMOVSX = {true}; | |
| const xImpl_MovExtend xMOVZX = {false}; | |
| const xImpl_CMov xCMOVA = {Jcc_Above}; | |
| const xImpl_CMov xCMOVAE = {Jcc_AboveOrEqual}; | |
| const xImpl_CMov xCMOVB = {Jcc_Below}; | |
| const xImpl_CMov xCMOVBE = {Jcc_BelowOrEqual}; | |
| const xImpl_CMov xCMOVG = {Jcc_Greater}; | |
| const xImpl_CMov xCMOVGE = {Jcc_GreaterOrEqual}; | |
| const xImpl_CMov xCMOVL = {Jcc_Less}; | |
| const xImpl_CMov xCMOVLE = {Jcc_LessOrEqual}; | |
| const xImpl_CMov xCMOVZ = {Jcc_Zero}; | |
| const xImpl_CMov xCMOVE = {Jcc_Equal}; | |
| const xImpl_CMov xCMOVNZ = {Jcc_NotZero}; | |
| const xImpl_CMov xCMOVNE = {Jcc_NotEqual}; | |
| const xImpl_CMov xCMOVO = {Jcc_Overflow}; | |
| const xImpl_CMov xCMOVNO = {Jcc_NotOverflow}; | |
| const xImpl_CMov xCMOVC = {Jcc_Carry}; | |
| const xImpl_CMov xCMOVNC = {Jcc_NotCarry}; | |
| const xImpl_CMov xCMOVS = {Jcc_Signed}; | |
| const xImpl_CMov xCMOVNS = {Jcc_Unsigned}; | |
| const xImpl_CMov xCMOVPE = {Jcc_ParityEven}; | |
| const xImpl_CMov xCMOVPO = {Jcc_ParityOdd}; | |
| const xImpl_Set xSETA = {Jcc_Above}; | |
| const xImpl_Set xSETAE = {Jcc_AboveOrEqual}; | |
| const xImpl_Set xSETB = {Jcc_Below}; | |
| const xImpl_Set xSETBE = {Jcc_BelowOrEqual}; | |
| const xImpl_Set xSETG = {Jcc_Greater}; | |
| const xImpl_Set xSETGE = {Jcc_GreaterOrEqual}; | |
| const xImpl_Set xSETL = {Jcc_Less}; | |
| const xImpl_Set xSETLE = {Jcc_LessOrEqual}; | |
| const xImpl_Set xSETZ = {Jcc_Zero}; | |
| const xImpl_Set xSETE = {Jcc_Equal}; | |
| const xImpl_Set xSETNZ = {Jcc_NotZero}; | |
| const xImpl_Set xSETNE = {Jcc_NotEqual}; | |
| const xImpl_Set xSETO = {Jcc_Overflow}; | |
| const xImpl_Set xSETNO = {Jcc_NotOverflow}; | |
| const xImpl_Set xSETC = {Jcc_Carry}; | |
| const xImpl_Set xSETNC = {Jcc_NotCarry}; | |
| const xImpl_Set xSETS = {Jcc_Signed}; | |
| const xImpl_Set xSETNS = {Jcc_Unsigned}; | |
| const xImpl_Set xSETPE = {Jcc_ParityEven}; | |
| const xImpl_Set xSETPO = {Jcc_ParityOdd}; | |
| } // end namespace x86Emitter |