2009-04-14 12:37:48 +00:00
|
|
|
/* 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
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ix86 core v0.9.0
|
|
|
|
*
|
|
|
|
* Original Authors (v0.6.2 and prior):
|
|
|
|
* linuzappz <linuzappz@pcsx.net>
|
|
|
|
* alexey silinov
|
|
|
|
* goldfinger
|
|
|
|
* zerofrog(@gmail.com)
|
|
|
|
*
|
|
|
|
* Authors of v0.9.0:
|
|
|
|
* Jake.Stine(@gmail.com)
|
|
|
|
* cottonvibes(@gmail.com)
|
|
|
|
* sudonim(1@gmail.com)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "PrecompiledHeader.h"
|
2009-07-03 00:49:40 +00:00
|
|
|
#include "internal.h"
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-15 15:45:52 +00:00
|
|
|
namespace x86Emitter {
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-19 02:14:50 +00:00
|
|
|
using namespace Internal;
|
|
|
|
|
2009-04-24 11:25:10 +00:00
|
|
|
const xImpl_JmpCall<true> xJMP;
|
|
|
|
const xImpl_JmpCall<false> xCALL;
|
2009-04-19 02:14:50 +00:00
|
|
|
|
2009-04-15 15:45:52 +00:00
|
|
|
// ------------------------------------------------------------------------
|
2009-04-20 03:10:05 +00:00
|
|
|
void xSmartJump::SetTarget()
|
2009-04-14 12:37:48 +00:00
|
|
|
{
|
2009-04-24 11:25:10 +00:00
|
|
|
u8* target = xGetPtr();
|
2009-04-15 15:45:52 +00:00
|
|
|
if( m_baseptr == NULL ) return;
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-24 11:25:10 +00:00
|
|
|
xSetPtr( m_baseptr );
|
2009-04-15 15:45:52 +00:00
|
|
|
u8* const saveme = m_baseptr + GetMaxInstructionSize();
|
2009-04-24 11:44:07 +00:00
|
|
|
xJccKnownTarget( m_cc, target, true );
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-15 15:45:52 +00:00
|
|
|
// Copy recompiled data inward if the jump instruction didn't fill the
|
|
|
|
// alloted buffer (means that we optimized things to a j8!)
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-24 11:25:10 +00:00
|
|
|
const int spacer = (sptr)saveme - (sptr)xGetPtr();
|
2009-04-15 15:45:52 +00:00
|
|
|
if( spacer != 0 )
|
2009-04-14 12:37:48 +00:00
|
|
|
{
|
2009-04-24 11:25:10 +00:00
|
|
|
u8* destpos = xGetPtr();
|
2009-04-19 02:14:50 +00:00
|
|
|
const int copylen = (sptr)target - (sptr)saveme;
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-15 15:45:52 +00:00
|
|
|
memcpy_fast( destpos, saveme, copylen );
|
2009-04-24 11:25:10 +00:00
|
|
|
xSetPtr( target - spacer );
|
2009-04-14 12:37:48 +00:00
|
|
|
}
|
2009-04-19 02:14:50 +00:00
|
|
|
}
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-20 03:10:05 +00:00
|
|
|
xSmartJump::~xSmartJump()
|
2009-04-19 02:14:50 +00:00
|
|
|
{
|
|
|
|
SetTarget();
|
|
|
|
m_baseptr = NULL; // just in case (sometimes helps in debugging too)
|
2009-04-14 12:37:48 +00:00
|
|
|
}
|
|
|
|
|
2009-05-07 08:21:57 +00:00
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Emits a 32 bit jump, and returns a pointer to the 32 bit displacement.
|
|
|
|
// (displacements should be assigned relative to the end of the jump instruction,
|
|
|
|
// or in other words *(retval+1) )
|
|
|
|
__emitinline s32* xJcc32( JccComparisonType comparison, s32 displacement )
|
|
|
|
{
|
|
|
|
if( comparison == Jcc_Unconditional )
|
|
|
|
xWrite8( 0xe9 );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xWrite8( 0x0f );
|
|
|
|
xWrite8( 0x80 | comparison );
|
|
|
|
}
|
|
|
|
xWrite<s32>( displacement );
|
|
|
|
|
|
|
|
return ((s32*)xGetPtr()) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Emits a 32 bit jump, and returns a pointer to the 8 bit displacement.
|
|
|
|
// (displacements should be assigned relative to the end of the jump instruction,
|
|
|
|
// or in other words *(retval+1) )
|
|
|
|
__emitinline s8* xJcc8( JccComparisonType comparison, s8 displacement )
|
|
|
|
{
|
|
|
|
xWrite8( (comparison == Jcc_Unconditional) ? 0xeb : (0x70 | comparison) );
|
|
|
|
xWrite<s8>( displacement );
|
|
|
|
return (s8*)xGetPtr() - 1;
|
|
|
|
}
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-15 15:45:52 +00:00
|
|
|
// ------------------------------------------------------------------------
|
|
|
|
// Writes a jump at the current x86Ptr, which targets a pre-established target address.
|
|
|
|
// (usually a backwards jump)
|
|
|
|
//
|
2009-04-20 03:10:05 +00:00
|
|
|
// slideForward - used internally by xSmartJump to indicate that the jump target is going
|
2009-04-15 15:45:52 +00:00
|
|
|
// to slide forward in the event of an 8 bit displacement.
|
|
|
|
//
|
2009-04-24 13:49:00 +00:00
|
|
|
__emitinline void Internal::xJccKnownTarget( JccComparisonType comparison, const void* target, bool slideForward )
|
2009-04-14 12:37:48 +00:00
|
|
|
{
|
2009-04-15 15:45:52 +00:00
|
|
|
// Calculate the potential j8 displacement first, assuming an instruction length of 2:
|
2009-05-07 08:21:57 +00:00
|
|
|
sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2);
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-15 15:45:52 +00:00
|
|
|
const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0;
|
|
|
|
displacement8 -= slideVal;
|
2009-04-14 12:37:48 +00:00
|
|
|
|
2009-04-15 15:45:52 +00:00
|
|
|
// if the following assert fails it means we accidentally used slideForard on a backward
|
|
|
|
// jump (which is an invalid operation since there's nothing to slide forward).
|
2009-05-22 00:35:09 +00:00
|
|
|
if( slideForward )
|
2009-04-15 15:45:52 +00:00
|
|
|
{
|
2009-05-22 00:35:09 +00:00
|
|
|
// jASSUME has an else statement in it that would be abiguous without the brackets.
|
|
|
|
jASSUME( displacement8 >= 0 );
|
2009-04-14 12:37:48 +00:00
|
|
|
}
|
2009-04-15 15:45:52 +00:00
|
|
|
|
|
|
|
if( is_s8( displacement8 ) )
|
2009-05-07 08:21:57 +00:00
|
|
|
xJcc8( comparison, displacement8 );
|
2009-04-15 15:45:52 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// Perform a 32 bit jump instead. :(
|
2009-05-07 08:21:57 +00:00
|
|
|
s32* bah = xJcc32( comparison );
|
|
|
|
*bah = (s32)target - (s32)xGetPtr();
|
2009-04-14 12:37:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-24 11:25:10 +00:00
|
|
|
// Low-level jump instruction! Specify a comparison type and a target in void* form, and
|
|
|
|
// a jump (either 8 or 32 bit) is generated.
|
2009-04-24 13:49:00 +00:00
|
|
|
__emitinline void xJcc( JccComparisonType comparison, const void* target )
|
2009-04-24 11:25:10 +00:00
|
|
|
{
|
2009-04-24 11:44:07 +00:00
|
|
|
xJccKnownTarget( comparison, target, false );
|
2009-04-24 11:25:10 +00:00
|
|
|
}
|
|
|
|
|
2009-04-24 13:49:00 +00:00
|
|
|
}
|
|
|
|
|