private void AnalyzeBranches()
{
SkipPC = new HashSet<uint>();
AnalyzedPC = new HashSet<uint>();
var BranchesToAnalyze = new Queue<uint>();
Labels[EntryPC] = AstLabel.CreateLabel("EntryPoint");
uint EndPC = (uint)InstructionReader.EndPC;
PC = EntryPC;
MinPC = uint.MaxValue;
MaxPC = uint.MinValue;
BranchesToAnalyze.Enqueue(EntryPC);
while (true)
{
HandleNewBranch: ;
bool EndOfBranchFound = false;
if (BranchesToAnalyze.Count == 0) break;
for (PC = BranchesToAnalyze.Dequeue(); PC <= EndPC; PC += 4)
{
// If already analyzed, stop scanning this branch.
if (AnalyzedPC.Contains(PC)) break;
AnalyzedPC.Add(PC);
//Console.WriteLine("%08X".Sprintf(PC));
if (AnalyzedPC.Count > MaxNumberOfInstructions)
{
throw (new InvalidDataException(String.Format("Code sequence too long: >= {0} at 0x{1:X8}", MaxNumberOfInstructions, EntryPC)));
}
UpdateMinMax(PC);
//Console.WriteLine(" PC:{0:X}", PC);
var Instruction = InstructionReader[PC];
var BranchInfo = DynarecBranchAnalyzer.GetBranchInfo(Instruction);
var DisassemblerInfo = MipsDisassembler.Disassemble(PC, Instruction);
LogInstruction(PC, Instruction);
// Break
if (DisassemblerInfo.InstructionInfo.Name == "break")
{
break;
}
// Branch instruction.
//else if (BranchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.JumpAlways))
else if (BranchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.JumpInstruction))
{
//Console.WriteLine("Instruction");
var JumpAddress = Instruction.GetJumpAddress(Memory, PC);
// Located a jump-always instruction with a delayed slot. Process next instruction too.
if (BranchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.AndLink))
{
// Just a function call. Continue analyzing.
}
else
{
if (PspMemory.IsAddressValid(JumpAddress))
{
if (!LabelsJump.ContainsKey(JumpAddress))
{
if (AddressInsideFunction(JumpAddress))
{
//Console.WriteLine("JumpAddress: {0:X8}", JumpAddress);
LabelsJump[JumpAddress] = AstLabel.CreateLabel(String.Format("Jump_0x{0:X8}", JumpAddress));
BranchesToAnalyze.Enqueue(JumpAddress);
}
}
}
EndOfBranchFound = true;
continue;
}
}
else if (BranchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.BranchOrJumpInstruction))
{
var BranchAddress = Instruction.GetBranchAddress(PC);
if (!Labels.ContainsKey(BranchAddress))
{
//Console.WriteLine("BranchAddress: {0:X8}", BranchAddress);
UpdateMinMax(BranchAddress);
Labels[BranchAddress] = AstLabel.CreateLabel(String.Format("Label_0x{0:X8}", BranchAddress));
BranchesToAnalyze.Enqueue(BranchAddress);
}
}
else if (BranchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.SyscallInstruction))
{
// On this special Syscall
if (Instruction.CODE == SyscallInfo.NativeCallSyscallCode)
{
//PC += 4;
goto HandleNewBranch;
}
}
// Jump-Always found. And we have also processed the delayed branch slot. End the branch.
if (EndOfBranchFound)
{
EndOfBranchFound = false;
goto HandleNewBranch;
}
}
}
//Console.WriteLine("FunctionSegment({0:X8}-{1:X8})", MinPC, MaxPC);
foreach (var LabelAddress in LabelsJump.Keys.ToArray())
{
if (!AddressInsideFunction(LabelAddress))
{
LabelsJump.Remove(LabelAddress);
}
}
this.CpuEmitter.BranchCount = Labels.Count;
}