public static AstNodeStm AnalyzeFunction(IMemory2 Memory, uint PC) { #if DEBUG_DYNAREC Console.WriteLine("AnalyzeFunction: {0:X8}", PC); #endif var Reader = (SwitchReadWordDelegate)(() => { var Ret = (uint)Memory.Read2(PC); //Console.WriteLine("{0:X4}: {1:X4}", PC, Ret); PC += 2; return Ret; }); HashSet<uint> AnalyzedPC = new HashSet<uint>(); var DynarecContext = new DynarecContextChip8(); Queue<uint> BranchesToAnalyze = new Queue<uint>(); var MinPC = uint.MaxValue; var MaxPC = uint.MinValue; BranchesToAnalyze.Enqueue(PC); var DecodeInstructionInfo = Chip8Dynarec.DecodeInstructionInfo.Value; var DecodeBranchContext = Chip8Dynarec.DecodeBranchContext.Value; var DecodeDynarec = Chip8Dynarec.DecodeDynare.Value; var AddLabelForPC = (Action<uint>)((_PC) => { DynarecContext.PCToLabel[_PC] = AstLabel.CreateLabel(String.Format("Label_{0:X8}", _PC)); }); int InstructionCount = 0; // PASS1: Branch analyzing #if DEBUG_DYNAREC Console.WriteLine("- PASS 1 ------------------------------------"); #endif while (BranchesToAnalyze.Count > 0) { PC = BranchesToAnalyze.Dequeue(); #if DEBUG_DYNAREC Console.WriteLine("Analyzing: {0:X8}", PC); #endif AddLabelForPC(PC); while (true) { //Console.ReadKey(); // Already analyzed. if (AnalyzedPC.Contains(PC)) { break; } AnalyzedPC.Add(PC); MinPC = Math.Min(PC, MinPC); MaxPC = Math.Min(PC, MaxPC); var CurrentPC = PC; PC = CurrentPC; var Instruction = DecodeInstructionInfo(Reader); var EndPC = PC; PC = CurrentPC; var BranchInfo = DecodeBranchContext(Reader, new BranchContext(CurrentPC, EndPC)); if (Instruction == null) { //throw (new Exception("Invalid!")); #if DEBUG_DYNAREC Console.WriteLine("{0:X4}: Invalid Instruction", CurrentPC); #endif } else { #if DEBUG_DYNAREC Console.WriteLine("{0:X4}: {1} : {2}", CurrentPC, Instruction.InstructionInfo.Name, BranchInfo.BranchType); #endif // Must follow jumps. if (BranchInfo.FollowJumps) { foreach (var JumpAddress in BranchInfo.PossibleJumpList) { #if DEBUG_DYNAREC Console.WriteLine("{0:X4}: Enqueueing BranchesToAnalyze {1:X4}", CurrentPC, JumpAddress); #endif BranchesToAnalyze.Enqueue(JumpAddress); } } // Stop exploring this branch. if (!BranchInfo.ContinueAnalyzing) { break; } } } } // PASS2: Code generation var Ast = ast.Statements(); var FlushInstructionCount = (Action)(() => { if (InstructionCount > 0) { Ast.AddStatement(ast.Assign(DynarecContext.GetInstructionCount(), DynarecContext.GetInstructionCount() + InstructionCount)); InstructionCount = 0; } }); #if DEBUG_DYNAREC Console.WriteLine("- PASS 2 ------------------------------------"); #endif foreach (var CurrentPC in AnalyzedPC.OrderBy(Item => Item)) { PC = CurrentPC; InstructionCount++; if (DynarecContext.PCToLabel.ContainsKey(PC)) { FlushInstructionCount(); Ast.AddStatement(ast.Label(DynarecContext.PCToLabel[PC])); } DynarecContext.CurrentPC = PC; PC = CurrentPC; DecodeInstructionInfo(Reader); DynarecContext.EndPC = PC; PC = CurrentPC; var BranchInfo = DecodeBranchContext(Reader, new BranchContext(DynarecContext.CurrentPC, DynarecContext.EndPC)); PC = CurrentPC; var DynarecResult = DecodeDynarec(Reader, DynarecContext); if (BranchInfo.IsJumpInstruction) { FlushInstructionCount(); if (BranchInfo.BranchType == BranchType.NoFollowAnalyzedAddresses) { Ast.AddStatement(DynarecContext.GetDynarecTick()); } } Ast.AddStatement(DynarecResult.AstNodeStm); } FlushInstructionCount(); Ast.AddStatement(ast.Return()); //Console.WriteLine(GeneratorCSharp.GenerateString(Ast)); return Ast; //Console.ReadKey(); //Console.WriteLine(); //Console.WriteLine(DecodeInstructionInfo(Reader)); //Console.WriteLine(DecodeInstructionInfo(Reader)); //Console.WriteLine(DecodeInstructionInfo(Reader)); //Console.WriteLine(DecodeInstructionInfo(Reader)); //DecodeInstructionInfo(); }