Пример #1
0
        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();
        }