Exemple #1
0
            //static int DummyTempCounter = 0;

            /// <summary>
            /// PASS 2: Generate code and put labels;
            /// </summary>
            private AstNodeStmContainer GenerateCode()
            {
                foreach (var label in _labels.ToArray())
                {
                    if (!(label.Key >= _minPc && label.Key <= _maxPc))
                    {
                        _labels.Remove(label.Key);
                    }
                }
                //AnalyzedPC

                _instructionsEmitedSinceLastWaypoint = 0;

                //Debug.WriteLine("PASS2: MinPC:{0:X}, MaxPC:{1:X}", MinPC, MaxPC);

                // Jumps to the entry point.
                var nodes = new AstNodeStmContainer();

                if (!_labels.ContainsKey(_entryPc))
                {
                    throw new KeyNotFoundException($"Can't find key {_entryPc:X} in list [{_labels.Select(it => $"{it.Key:X}").JoinToString(",")}]");
                }
                nodes.AddStatement(_ast.GotoAlways(_labels[_entryPc]));

                for (_pc = _minPc; _pc <= _maxPc;)
                {
                    if (!_analyzedPc.Contains(_pc))
                    {
                        _pc += 4;
                        continue;
                    }
                    uint        currentInstructionPc = _pc;
                    Instruction currentInstruction   = _instructionReader[_pc];
                    _instructionsProcessed++;

                    var branchInfo = DynarecBranchAnalyzer.GetBranchInfo(currentInstruction.Value);

                    // Delayed branch instruction.
                    if ((branchInfo & DynarecBranchAnalyzer.JumpFlags.BranchOrJumpInstruction) != 0)
                    {
                        _instructionsEmitedSinceLastWaypoint += 2;
                        nodes.AddStatement(EmitInstructionCountIncrement(true));

                        var branchAddress = currentInstruction.GetBranchAddress(_pc);

                        if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.JumpInstruction))
                        {
                            TryPutLabelAt(_pc, nodes);

                            var delayedBranchInstruction = _GetAstCpuInstructionAT(_pc + 4); // Delayed
                            var jumpInstruction          = _GetAstCpuInstructionAT(_pc + 0); // Jump

#if !DISABLE_JUMP_GOTO
                            var jumpInstruction2 = _cpuEmitter.LoadAt(_pc + 0);
                            var jumpDisasm       = _mipsDisassembler.Disassemble(_pc + 0, jumpInstruction2);
                            var jumpJumpPc       = jumpDisasm.Instruction.GetJumpAddress(_memory, jumpDisasm.InstructionPc);

                            // An internal jump.
                            if (
                                jumpDisasm.InstructionInfo.Name == "j" &&
                                _labelsJump.ContainsKey(jumpJumpPc)
                                )
                            {
                                jumpInstruction = new AstNodeStmPspInstruction(jumpDisasm,
                                                                               _ast.GotoAlways(_labelsJump[jumpJumpPc]));

                                //Console.WriteLine(
                                //	"{0}: {1} : Function({2:X8}-{3:X8})",
                                //	DummyTempCounter,
                                //	GeneratorCSharpPsp.GenerateString<GeneratorCSharpPsp>(AstOptimizerPsp.GlobalOptimize(CpuProcessor, JumpInstruction)),
                                //	MinPC, MaxPC
                                //);

                                //DummyTempCounter++;
                            }
                            else if (jumpDisasm.InstructionInfo.Name == "j" || jumpDisasm.InstructionInfo.Name == "jal")
                            {
                                CallingPCs.Add(jumpJumpPc);
                            }
#endif

                            // Put delayed instruction first.
                            nodes.AddStatement(delayedBranchInstruction);
                            // A jump outside the current function.
                            nodes.AddStatement(jumpInstruction);

                            _pc += 8;
                        }
                        else
                        {
                            // Branch instruction.
                            nodes.AddStatement(EmitCpuInstruction());

                            //if ((BranchInfo & CpuBranchAnalyzer.Flags.Likely) != 0)
                            if (branchInfo.HasFlag(DynarecBranchAnalyzer.JumpFlags.Likely))
                            {
                                //Console.WriteLine("Likely");
                                // Delayed instruction.
                                nodes.AddStatement(_cpuEmitter._branch_likely(EmitCpuInstruction()));
                            }
                            else
                            {
                                //Console.WriteLine("Not Likely");
                                // Delayed instruction.
                                nodes.AddStatement(EmitCpuInstruction());
                            }

                            if (currentInstructionPc + 4 != branchAddress)
                            {
                                if (_labels.ContainsKey(branchAddress))
                                {
                                    nodes.AddStatement(_cpuEmitter._branch_post(_labels[branchAddress], branchAddress));
                                }
                                // Code not reached.
                                else
                                {
                                    throw new InvalidOperationException("!Labels.ContainsKey(BranchAddress)");
                                }
                            }
                            else
                            {
                                throw new InvalidOperationException("Invalid branch!");
                            }
                        }
                    }
                    // Normal instruction.
                    else
                    {
                        // Syscall instruction.
                        if ((branchInfo & DynarecBranchAnalyzer.JumpFlags.SyscallInstruction) != 0)
                        {
                            nodes.AddStatement(StorePc());
                        }
                        nodes.AddStatement(EmitCpuInstruction());
                        if ((branchInfo & DynarecBranchAnalyzer.JumpFlags.SyscallInstruction) != 0)
                        {
                            // On this special Syscall
                            if (currentInstruction.Code == SyscallInfo.NativeCallSyscallCode)
                            {
                                //PC += 4;
                                break;
                            }
                        }
                    }
                }

                //MipsMethodEmiter.GenerateIL(Nodes);
                ShowInstructionStats();

                //if (BreakPoint) IsDebuggerPresentDebugBreak();

                return(nodes);
            }
Exemple #2
0
            /// <summary>
            /// PASS 1: Analyze Branches
            /// </summary>
            private void AnalyzeBranches()
            {
                _skipPc     = new HashSet <uint>();
                _analyzedPc = new HashSet <uint>();
                var branchesToAnalyze = new Queue <uint>();

                _labels[_entryPc] = AstLabel.CreateLabel("EntryPoint");

                var endPc = _instructionReader.EndPc;

                _pc    = _entryPc;
                _minPc = uint.MaxValue;
                _maxPc = uint.MinValue;

                branchesToAnalyze.Enqueue(_entryPc);

                while (true)
                {
HandleNewBranch:
                    var 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(
                                      $"Code sequence too long: >= {MaxNumberOfInstructions} at 0x{_entryPc:X8}");
                        }

                        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($"Jump_0x{jumpAddress:X8}");
                                            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($"Label_0x{branchAddress:X8}");
                                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);
                    }
                }

                _cpuEmitter.BranchCount = _labels.Count;
            }