// 分岐(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; }