// ------------------------------------------------------------------------ // Writes a jump at the current x86Ptr, which targets a pre-established target address. // (usually a backwards jump) // // slideForward - used internally by xSmartJump to indicate that the jump target is going // to slide forward in the event of an 8 bit displacement. // __emitinline void xJccKnownTarget(JccComparisonType comparison, const void *target, bool slideForward) { // Calculate the potential j8 displacement first, assuming an instruction length of 2: sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2); const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0; displacement8 -= slideVal; if (slideForward) { pxAssertDev(displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!"); } if (is_s8(displacement8)) xJcc8(comparison, displacement8); else { // Perform a 32 bit jump instead. :( s32 *bah = xJcc32(comparison); sptr distance = (sptr)target - (sptr)xGetPtr(); #ifdef __x86_64__ // This assert won't physically happen on x86 targets pxAssertDev(distance >= -0x80000000LL && distance < 0x80000000LL, "Jump target is too far away, needs an indirect register"); #endif *bah = (s32)distance; } }
static void recRecompile() { // Look up the block... // (Mask the IOP address accordingly to account for the many various segments and // mirrors). u32 masked_pc = iopRegs.pc & IopMemory::AddressMask; if( masked_pc < 0x800000 ) masked_pc &= Ps2MemSize::IopRam-1; xBlocksMap::Blockmap_iterator blowme( g_PersState.xBlockMap.Map.find( masked_pc ) ); memzero_obj( g_BlockState ); //g_BlockState.pc = iopRegs.pc; if( blowme == g_PersState.xBlockMap.Map.end() ) { //Console::WriteLn( "IOP First-pass block at PC: 0x%08x (total blocks=%d)", params masked_pc, g_PersState.xBlockMap.Blocks.GetLength() ); recIR_FirstPassInterpreter(); jASSUME( iopRegs.evtCycleCountdown <= iopRegs.evtCycleDuration ); if( iopRegs.evtCycleCountdown <= 0 ) iopRegs.ExecutePendingEvents(); //if( !IsIopRamPage( masked_pc ) ) // disable block checking for non-ram (rom, rom1, etc) // m_blockspace.ramlen = 0; g_PersState.xBlockMap.Map[masked_pc] = g_PersState.xBlockMap.Blocks.GetLength(); g_PersState.xBlockMap.Blocks.New().Assign( m_blockspace ); } else { recBlockItem& mess( g_PersState.xBlockMap.Blocks[blowme->second] ); if( !mess.InstOptInfo.IsDisposed() ) { //Console::WriteLn( "IOP Second-pass block at PC: 0x%08x (total blocks=%d)", params masked_pc, g_PersState.xBlockMap.Blocks.GetLength() ); m_tempIR.GenerateIR( mess ); mess.InstOptInfo.Dispose(); m_x86blockstate.AssignBlock( m_tempIR ); m_x86blockstate.RegisterMapper(); g_BlockState.xBlockPtr = m_xBlock_CurPtr; m_x86blockstate.EmitSomeExecutableGoodness(); m_xBlock_CurPtr = xGetPtr(); uptr temp = m_tbl_TranslatePC[masked_pc>>XlatePC_PageBitShift]; uptr* dispatch_ptr = (uptr*)(temp + (masked_pc & XlatePC_PageMask)); *dispatch_ptr = (uptr)g_BlockState.xBlockPtr; } }
// ------------------------------------------------------------------------ // 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; }
void xSmartJump::SetTarget() { u8* target = xGetPtr(); if( m_baseptr == NULL ) return; xSetPtr( m_baseptr ); u8* const saveme = m_baseptr + GetMaxInstructionSize(); xJccKnownTarget( m_cc, target, true ); // Copy recompiled data inward if the jump instruction didn't fill the // alloted buffer (means that we optimized things to a j8!) const int spacer = (sptr)saveme - (sptr)xGetPtr(); if( spacer != 0 ) { u8* destpos = xGetPtr(); const int copylen = (sptr)target - (sptr)saveme; memcpy_fast( destpos, saveme, copylen ); xSetPtr( target - spacer ); } }
// ------------------------------------------------------------------------ // Writes a jump at the current x86Ptr, which targets a pre-established target address. // (usually a backwards jump) // // slideForward - used internally by xSmartJump to indicate that the jump target is going // to slide forward in the event of an 8 bit displacement. // __emitinline void xJccKnownTarget( JccComparisonType comparison, const void* target, bool slideForward ) { // Calculate the potential j8 displacement first, assuming an instruction length of 2: sptr displacement8 = (sptr)target - (sptr)(xGetPtr() + 2); const int slideVal = slideForward ? ((comparison == Jcc_Unconditional) ? 3 : 4) : 0; displacement8 -= slideVal; if( slideForward ) { pxAssertDev( displacement8 >= 0, "Used slideForward on a backward jump; nothing to slide!" ); } if( is_s8( displacement8 ) ) xJcc8( comparison, displacement8 ); else { // Perform a 32 bit jump instead. :( s32* bah = xJcc32( comparison ); *bah = (s32)target - (s32)xGetPtr(); } }
// ------------------------------------------------------------------------ // void xBlocksMap::AddLink( u32 pc, JccComparisonType cctype ) { recBlockItem& destItem( _getItem( pc ) ); const xJumpLink& newlink( destItem.DependentLinks.AddNew( xJumpLink( xGetPtr(), cctype ) ) ); newlink.SetTarget( m_xBlockLut[pc / 4] ); if( destItem.x86len != 0 ) { // Sanity Check: if block is already compiled, then the BlockPtr should *not* be dispatcher. jASSUME( m_xBlockLut[pc / 4] != DynFunc::Dispatcher ); } }
void xForwardJumpBase::_setTarget(uint opsize) const { pxAssertDev(BasePtr != NULL, ""); sptr displacement = (sptr)xGetPtr() - (sptr)BasePtr; if (opsize == 1) { pxAssertDev(is_s8(displacement), "Emitter Error: Invalid short jump displacement."); BasePtr[-1] = (s8)displacement; } else { // full displacement, no sanity checks needed :D ((s32 *)BasePtr)[-1] = displacement; } }
xForwardJumpBase::xForwardJumpBase(uint opsize, JccComparisonType cctype) { pxAssert(opsize == 1 || opsize == 4); pxAssertDev(cctype != Jcc_Unknown, "Invalid ForwardJump conditional type."); BasePtr = (s8 *)xGetPtr() + ((opsize == 1) ? 2 : // j8's are always 2 bytes. ((cctype == Jcc_Unconditional) ? 5 : 6)); // j32's are either 5 or 6 bytes if (opsize == 1) xWrite8((cctype == Jcc_Unconditional) ? 0xeb : (0x70 | cctype)); else { if (cctype == Jcc_Unconditional) xWrite8(0xe9); else { xWrite8(0x0f); xWrite8(0x80 | cctype); } } xAdvancePtr(opsize); }
// ------------------------------------------------------------------------ // 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; }