Example #1
0
 // 分岐(jumpを含む)かどうか
 bool IsBranch(int code)         
 {
     return IsConditionalBranch(code) || IsUnconditionalBranch(code);
 }
//*************************************************************************************
//
//*************************************************************************************
CTraceRecorder::EUpdateTraceStatus	CTraceRecorder::UpdateTrace( u32 address,
																 bool branch_delay_slot,
																 bool branch_taken,
																 OpCode op_code,
																 CFragment * p_fragment )
{
	DAEDALUS_ASSERT( mTracing, "We're not tracing" );

	bool				want_to_stop( p_fragment != NULL );

	if( mTraceBuffer.size() > MAX_TRACE_LENGTH )
	{
		DBGConsole_Msg(0, "Hit max trace size!");
		want_to_stop = true;
	}

	// Terminate if the current instruction is in the fragment cache or the trace reaches a specified size
	if( want_to_stop && (mActiveBranchIdx == INVALID_IDX) )
	{
		DAEDALUS_ASSERT( mActiveBranchIdx == INVALID_IDX, "Exiting trace while in the middle of handling branch!" );
		// Stop immediately so we can be sure of linking up with fragment
		mTracing = false;
		mExpectedExitTraceAddress = address;
		return UTS_CREATE_FRAGMENT;
	}

	//
	//	Figure out whether to terminate this trace after adding this instruction
	//
	bool	stop_trace_on_exit( false );

	//
	//	We want to record the delay slot op for the active branch
	//
	if( mActiveBranchIdx != INVALID_IDX )
	{
		DAEDALUS_ASSERT( mActiveBranchIdx < mBranchDetails.size(), "Branch index is out of bounds" );
		mBranchDetails[ mActiveBranchIdx ].DelaySlotTraceIndex = mTraceBuffer.size();

		if (mBranchDetails[ mActiveBranchIdx ].SpeedHack == SHACK_POSSIBLE)
		{
			if (op_code._u32 == 0)
			{
				mBranchDetails[ mActiveBranchIdx ].SpeedHack = SHACK_SKIPTOEVENT;

			}
#ifndef DAEDALUS_SILENT
			else if (op_code.op == OP_ADDIU || op_code.op == OP_DADDI || op_code.op == OP_ADDI || op_code.op == OP_DADDIU)
			{	// We don't handle COPYREG SPEEDHACKS
				mBranchDetails[ mActiveBranchIdx ].SpeedHack = SHACK_COPYREG;
			}
#endif
		}

		mActiveBranchIdx = INVALID_IDX;
	}

	// If we had to terminate on the last branch (e.g. for an indirect jump)
	// or if we're jumping backwards, terminate the run when we exit
	if( mStopTraceAfterDelaySlot && branch_delay_slot )
	{
		mStopTraceAfterDelaySlot = false;
		stop_trace_on_exit = true;
	}

	//
	//	Update the expected trace exit address
	//	We assume that if we'll exit on the next instruction (assuming this isn't a branch)
	//
	if( !branch_delay_slot )
	{
		mExpectedExitTraceAddress = address + 4;
	}

	StaticAnalysis::RegisterUsage usage;
	StaticAnalysis::Analyse(op_code,usage);

	//
	//	If this is a branch, we need to determine if it was taken or not.
	//	We store a information about the 'off-trace' target.
	//	If the branch was taken, we need to flip the condition of the
	//	branch so that anything failing the test is directed off our trace
	//
	u32		branch_idx( INVALID_IDX );

	ER4300BranchType	branch_type( usage.BranchType );
	if( branch_type != BT_NOT_BRANCH )
	{
		SBranchDetails	details;

		details.Likely = IsBranchTypeLikely( branch_type );

		if( branch_type == BT_ERET )
		{
			stop_trace_on_exit = true;
			details.Eret = true;
			details.Direct = false;
			details.TargetAddress = INDIRECT_EXIT_ADDRESS;

			mExpectedExitTraceAddress = details.TargetAddress;
		}
		else if( !IsConditionalBranch( branch_type ) )
		{
			details.Direct = IsBranchTypeDirect( branch_type );
			details.TargetAddress = gCPUState.TargetPC;
			details.ConditionalBranchTaken = true;

			mExpectedExitTraceAddress = details.TargetAddress;

			if (!details.Direct || gCPUState.TargetPC <= gCPUState.CurrentPC)
			{
				// all indirect call will stop the trace
				mStopTraceAfterDelaySlot = true;
			}

			if (details.Direct && gCPUState.TargetPC == gCPUState.CurrentPC)
			{
				details.SpeedHack = SHACK_POSSIBLE;
			}
		}
		else
		{
			// Must be conditional, direct
			DAEDALUS_ASSERT( IsBranchTypeDirect( branch_type ), "Not expecting an indirect branch here" );

			if( branch_taken )
			{
				// XXXXXX should be able to get this some other way?
				bool	backwards( gCPUState.TargetPC <= gCPUState.CurrentPC );

				if( backwards )
				{
					mStopTraceAfterDelaySlot = true;
				}

				if (gCPUState.TargetPC == gCPUState.CurrentPC)
				{
					details.SpeedHack = SHACK_POSSIBLE;
				}
			}

			u32		branch_target_address( GetBranchTarget( address, op_code, branch_type ) );
			u32		fallthrough_address( address + 8 );

			u32		target_address;
			if( branch_taken )
			{
				// We're following the branch.
				target_address = fallthrough_address;
				mExpectedExitTraceAddress = branch_target_address;
			}
			else
			{
				// We're not following the branch, and falling through.
				target_address = branch_target_address;
				mExpectedExitTraceAddress = fallthrough_address;
			}

			details.ConditionalBranchTaken = branch_taken;
			details.Direct = true;
			details.TargetAddress = target_address;
		}

		if( !details.Direct )
		{
			mNeedIndirectExitMap = true;
		}

		mActiveBranchIdx = mBranchDetails.size();
		branch_idx = mBranchDetails.size();
		mBranchDetails.push_back( details );
	}

	// Add this op to the trace buffer.
	STraceEntry		entry = { address, op_code, usage, branch_idx, branch_delay_slot };

	mTraceBuffer.push_back( entry );

	if( stop_trace_on_exit )
	{
		DAEDALUS_ASSERT( branch_type == BT_ERET || mActiveBranchIdx == INVALID_IDX, "Exiting trace while in the middle of handling branch!" );

		mTracing = false;
		return UTS_CREATE_FRAGMENT;
	}

	return UTS_CONTINUE_TRACE;
}