示例#1
0
 public void CreateDelegateTest()
 {
     var PspConfig = new PspConfig();
     var PspEmulatorContext = new PspEmulatorContext(PspConfig);
     PspEmulatorContext.SetInstanceType<PspMemory, LazyPspMemory>();
     var Memory = PspEmulatorContext.GetInstance<PspMemory>();
     var Processor = PspEmulatorContext.GetInstance<CpuProcessor>();
     var CpuThreadState = new CpuThreadState(Processor);
     var MipsEmiter = new MipsMethodEmiter(new MipsEmiter(), Processor, 0);
     CpuThreadState.GPR[1] = 1;
     CpuThreadState.GPR[2] = 2;
     CpuThreadState.GPR[3] = 3;
     MipsEmiter.OP_3REG_Unsigned(1, 2, 2, () => { MipsEmiter.SafeILGenerator.BinaryOperation(SafeBinaryOperator.AdditionSigned); });
     MipsEmiter.OP_3REG_Unsigned(0, 2, 2, () => { MipsEmiter.SafeILGenerator.BinaryOperation(SafeBinaryOperator.AdditionSigned); });
     MipsEmiter.OP_2REG_IMM_Signed(10, 0, 1000, () => { MipsEmiter.SafeILGenerator.BinaryOperation(SafeBinaryOperator.AdditionSigned); });
     MipsEmiter.CreateDelegate()(CpuThreadState);
     Assert.AreEqual(4, CpuThreadState.GPR[1]);
     Assert.AreEqual(0, CpuThreadState.GPR[0]);
     Assert.AreEqual(1000, CpuThreadState.GPR[10]);
 }
示例#2
0
        private Action<CpuThreadState> CreateDelegateForMethodInfo(MethodInfo MethodInfo, HlePspFunctionAttribute HlePspFunctionAttribute)
        {
            var MipsMethodEmiter = new MipsMethodEmiter(HleState.MipsEmiter, HleState.CpuProcessor);
            int GprIndex = 4;
            int FprIndex = 0;

            var NotImplementedAttribute = (HlePspNotImplementedAttribute)MethodInfo.GetCustomAttributes(typeof(HlePspNotImplementedAttribute), true).FirstOrDefault();
            bool NotImplemented = (NotImplementedAttribute != null) ? NotImplementedAttribute.Notice : false;
            bool SkipLog = HlePspFunctionAttribute.SkipLog;

            var ParamInfoList = new List<ParamInfo>();

            Action CallAction = () =>
            {
                MipsMethodEmiter.ILGenerator.Emit(OpCodes.Ldarg_0);
                MipsMethodEmiter.ILGenerator.Emit(OpCodes.Ldfld, typeof(CpuThreadState).GetField("ModuleObject"));
                MipsMethodEmiter.ILGenerator.Emit(OpCodes.Castclass, this.GetType());
                foreach (var ParameterInfo in MethodInfo.GetParameters())
                {
                    var ParameterType = ParameterInfo.ParameterType;

                    // The CpuThreadState
                    if (ParameterType == typeof(CpuThreadState))
                    {
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Ldarg_0);
                    }
                    // A stringz
                    else if (ParameterType == typeof(string))
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = ParameterType,
                        });
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Ldarg_0);
                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Call, typeof(HleModuleHost).GetMethod("StringFromAddress"));
                        GprIndex++;
                    }
                    // A pointer
                    else if (ParameterType.IsPointer)
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = typeof(uint),
                        });
                        MipsMethodEmiter._getmemptr(() =>
                        {
                            MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        }, Safe: true);
                        GprIndex++;
                    }
                    // A long type
                    else if (ParameterType == typeof(long) || ParameterType == typeof(ulong))
                    {
                        while (GprIndex % 2 != 0) GprIndex++;

                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = ParameterType,
                        });

                        MipsMethodEmiter.LoadGPRLong_Signed(GprIndex + 0);
                        /*
                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex + 0);
                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex + 1);
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Ldc_I4, 32);
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Shl);
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Or);
                        */
                        GprIndex += 2;
                    }
                    // A float register.
                    else if (ParameterType == typeof(float))
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Fpr,
                            RegisterIndex = FprIndex,
                            ParameterType = ParameterType,
                        });

                        MipsMethodEmiter.LoadFPR(FprIndex);
                        FprIndex++;
                    }
                    // An integer register
                    else
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = ParameterType,
                        });

                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        GprIndex++;
                    }
                    //MipsMethodEmiter.ILGenerator.Emit(OpCodes.ld
                }
                MipsMethodEmiter.ILGenerator.Emit(OpCodes.Call, MethodInfo);
            };

            if (MethodInfo.ReturnType == typeof(void))
            {
                CallAction();
            }
            else if (MethodInfo.ReturnType == typeof(long))
            {
                MipsMethodEmiter.SaveGPRLong(2, CallAction);
            }
            else
            {
                MipsMethodEmiter.SaveGPR(2, CallAction);
            }

            var Delegate = MipsMethodEmiter.CreateDelegate();
            return (CpuThreadState) =>
            {
                bool Trace = (!SkipLog && CpuThreadState.CpuProcessor.PspConfig.DebugSyscalls);

                if (NotImplemented)
                {
                    Trace = true;
                    ConsoleUtils.SaveRestoreConsoleState(() =>
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine(
                            "Not implemented {0}.{1}",
                            MethodInfo.DeclaringType.Name, MethodInfo.Name
                        );
                    });
                }

                var Out = Console.Out;
                if (NotImplemented)
                {
                    Out = Console.Error;
                }

                if (Trace)
                {
                    if (HleState.ThreadManager.Current != null)
                    {
                        Out.Write(
                            "Thread({0}:'{1}') : RA(0x{2:X})",
                            HleState.ThreadManager.Current.Id,
                            HleState.ThreadManager.Current.Name,
                            HleState.ThreadManager.Current.CpuThreadState.RA
                        );
                    }
                    else
                    {
                        Out.Write("NoThread:");
                    }
                    Out.Write(" : {0}.{1}", MethodInfo.DeclaringType.Name, MethodInfo.Name);
                    Out.Write("(");
                    int Count = 0;
                    foreach (var ParamInfo in ParamInfoList)
                    {
                        if (Count > 0) Out.Write(", ");
                        Out.Write("{0}:", ParamInfo.ParameterName);
                        switch (ParamInfo.RegisterType)
                        {
                            case HleModuleHost.ParamInfo.RegisterTypeEnum.Fpr:
                            case HleModuleHost.ParamInfo.RegisterTypeEnum.Gpr:
                                uint Int4 = (uint)CpuThreadState.GPR[ParamInfo.RegisterIndex];
                                uint Float4 = (uint)CpuThreadState.FPR[ParamInfo.RegisterIndex];
                                Out.Write("{0}", ToNormalizedTypeString(ParamInfo.ParameterType, CpuThreadState, Int4, Float4));
                                break;
                            default:
                                throw(new NotImplementedException());
                        }
                        Count++;
                    }
                    Out.Write(")");
                    //Console.WriteLine("");
                }

                CpuThreadState.ModuleObject = this;
                try
                {
                    Delegate(CpuThreadState);
                }
                catch (SceKernelException SceKernelException)
                {
                    CpuThreadState.GPR[2] = (int)SceKernelException.SceKernelError;
                }
                catch (SceKernelSelfStopUnloadModuleException SceKernelSelfStopUnloadModuleException)
                {
                    throw (SceKernelSelfStopUnloadModuleException);
                }
                catch (Exception Exception)
                {
                    throw (new Exception(
                        String.Format("ERROR calling {0}.{1}!", MethodInfo.DeclaringType.Name, MethodInfo.Name),
                        Exception
                    ));
                }
                finally
                {
                    if (Trace)
                    {
                        Out.WriteLine(" : {0}", ToNormalizedTypeString(MethodInfo.ReturnType, CpuThreadState, (uint)CpuThreadState.GPR[2], (float)CpuThreadState.FPR[0]));
                        Out.WriteLine("");
                    }
                }
            };
        }
示例#3
0
        static private Action <CpuThreadState> _CreateDelegateForPC(CpuProcessor CpuProcessor, Stream MemoryStream, uint EntryPC, out int InstructionsProcessed)
        {
            InstructionsProcessed = 0;

            if (EntryPC == 0)
            {
                if (MemoryStream is PspMemoryStream)
                {
                    throw (new InvalidOperationException("EntryPC can't be NULL"));
                }
            }

            if (CpuProcessor.PspConfig.TraceJIT)
            {
                Console.WriteLine("Emiting EntryPC=0x{0:X}", EntryPC);
            }

            MemoryStream.Position = EntryPC;
            if ((MemoryStream.Length >= 8) && new BinaryReader(MemoryStream).ReadUInt64() == 0x0000000003E00008)
            {
                Console.WriteLine("NullSub detected at 0x{0:X}!", EntryPC);
            }

            var InstructionReader = new InstructionReader(MemoryStream);
            var MipsMethodEmiter  = new MipsMethodEmiter(MipsEmiter, CpuProcessor);
            var ILGenerator       = MipsMethodEmiter.ILGenerator;
            var CpuEmiter         = new CpuEmiter(MipsMethodEmiter, InstructionReader, MemoryStream, CpuProcessor);

            uint PC;
            uint EndPC = (uint)MemoryStream.Length;
            uint MinPC = uint.MaxValue, MaxPC = uint.MinValue;

            var Labels            = new SortedDictionary <uint, Label>();
            var BranchesToAnalyze = new Queue <uint>();
            var AnalyzedPC        = new HashSet <uint>();

            Labels[EntryPC] = ILGenerator.DefineLabel();

            BranchesToAnalyze.Enqueue(EntryPC);

            // PASS1: Analyze and find labels.
            PC = EntryPC;
            //Debug.WriteLine("PASS1: (PC={0:X}, EndPC={1:X})", PC, EndPC);

            var GlobalInstructionStats = CpuProcessor.GlobalInstructionStats;
            var InstructionStats       = new Dictionary <string, uint>();
            var NewInstruction         = new Dictionary <string, bool>();

            int MaxNumberOfInstructions = 8 * 1024;

            //int MaxNumberOfInstructions = 60;

            while (BranchesToAnalyze.Count > 0)
            {
                bool EndOfBranchFound = false;

                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 + ""));
                    }

                    MinPC = Math.Min(MinPC, PC);
                    MaxPC = Math.Max(MaxPC, PC);

                    //Console.WriteLine("    PC:{0:X}", PC);

                    CpuEmiter.LoadAT(PC);

                    var BranchInfo = GetBranchInfo(CpuEmiter.Instruction.Value);
                    if (CpuProcessor.PspConfig.LogInstructionStats)
                    {
                        var InstructionName = GetInstructionName(CpuEmiter.Instruction.Value, null);

                        if (!InstructionStats.ContainsKey(InstructionName))
                        {
                            InstructionStats[InstructionName] = 0;
                        }
                        InstructionStats[InstructionName]++;

                        if (!GlobalInstructionStats.ContainsKey(InstructionName))
                        {
                            NewInstruction[InstructionName]         = true;
                            GlobalInstructionStats[InstructionName] = 0;
                        }

                        GlobalInstructionStats[InstructionName]++;
                        //var GlobalInstructionStats = CpuProcessor.GlobalInstructionStats;
                        //var InstructionStats = new Dictionary<string, uint>();
                        //var NewInstruction = new Dictionary<string, bool>();
                    }

                    // Branch instruction.
                    if ((BranchInfo & CpuBranchAnalyzer.Flags.JumpInstruction) != 0)
                    {
                        //Console.WriteLine("Instruction");
                        EndOfBranchFound = true;
                        continue;
                    }
                    else if ((BranchInfo & CpuBranchAnalyzer.Flags.BranchOrJumpInstruction) != 0)
                    {
                        var BranchAddress = CpuEmiter.Instruction.GetBranchAddress(PC);
                        Labels[BranchAddress] = ILGenerator.DefineLabel();
                        BranchesToAnalyze.Enqueue(BranchAddress);

                        // Jump Always performed.

                        /*
                         * if ((BranchInfo & CpuBranchAnalyzer.Flags.JumpAlways) != 0)
                         * {
                         *      EndOfBranchFound = true;
                         *      continue;
                         * }
                         */
                    }
                    else if ((BranchInfo & CpuBranchAnalyzer.Flags.SyscallInstruction) != 0)
                    {
                        // On this special Syscall
                        if (CpuEmiter.Instruction.CODE == FunctionGenerator.NativeCallSyscallCode)
                        {
                            //PC += 4;
                            break;
                        }
                    }

                    // A Jump Always found. And we have also processed the delayed branch slot. End the branch.
                    if (EndOfBranchFound)
                    {
                        EndOfBranchFound = false;
                        break;
                    }
                }
            }

            // PASS2: Generate code and put labels;
            Action <uint> _EmitCpuInstructionAT = (_PC) =>
            {
                if (CpuProcessor.PspConfig.TraceJIT)
                {
                    ILGenerator.Emit(OpCodes.Ldarg_0);
                    ILGenerator.Emit(OpCodes.Ldc_I4, _PC);
                    ILGenerator.Emit(OpCodes.Call, typeof(CpuThreadState).GetMethod("Trace"));
                    Console.WriteLine("     PC=0x{0:X}", _PC);
                }

                CpuEmiter.LoadAT(_PC);
                CpuEmiterInstruction(CpuEmiter.Instruction.Value, CpuEmiter);
            };

            uint InstructionsEmitedSinceLastWaypoint = 0;

            Action StorePC = () =>
            {
                MipsMethodEmiter.SavePC(PC);
            };

            Action <bool> EmitInstructionCountIncrement = (bool CheckForYield) =>
            {
                if (!CpuProcessor.PspConfig.CountInstructionsAndYield)
                {
                    return;
                }

                //Console.WriteLine("EmiteInstructionCountIncrement: {0},{1}", InstructionsEmitedSinceLastWaypoint, CheckForYield);
                if (InstructionsEmitedSinceLastWaypoint > 0)
                {
                    MipsMethodEmiter.SaveStepInstructionCount(() =>
                    {
                        MipsMethodEmiter.LoadStepInstructionCount();
                        ILGenerator.Emit(OpCodes.Ldc_I4, InstructionsEmitedSinceLastWaypoint);
                        //ILGenerator.Emit(OpCodes.Add);
                        ILGenerator.Emit(OpCodes.Sub);
                    });
                    //ILGenerator.Emit(OpCodes.Ldc_I4, 100);
                    //ILGenerator.EmitCall(OpCodes.Call, typeof(Console).GetMethod("WriteLine"), new Type[] { typeof(int) });
                    InstructionsEmitedSinceLastWaypoint = 0;
                }

                if (CheckForYield)
                {
                    if (!CpuProcessor.PspConfig.BreakInstructionThreadSwitchingForSpeed)
                    {
                        var NoYieldLabel = ILGenerator.DefineLabel();
                        MipsMethodEmiter.LoadStepInstructionCount();
                        ILGenerator.Emit(OpCodes.Ldc_I4_0);
                        ILGenerator.Emit(OpCodes.Bgt, NoYieldLabel);
                        //ILGenerator.Emit(OpCodes.Ldc_I4, 1000000);
                        //ILGenerator.Emit(OpCodes.Blt, NoYieldLabel);
                        MipsMethodEmiter.SaveStepInstructionCount(() =>
                        {
                            ILGenerator.Emit(OpCodes.Ldc_I4_0);
                        });
                        StorePC();
                        ILGenerator.Emit(OpCodes.Ldarg_0);
                        ILGenerator.Emit(OpCodes.Call, typeof(CpuThreadState).GetMethod("Yield"));
                        //ILGenerator.Emit(OpCodes.Call, typeof(GreenThread).GetMethod("Yield"));
                        ILGenerator.MarkLabel(NoYieldLabel);
                    }
                }
            };

            Action EmitCpuInstruction = () =>
            {
                if (CpuProcessor.NativeBreakpoints.Contains(PC))
                {
                    ILGenerator.Emit(OpCodes.Call, typeof(DebugUtils).GetMethod("IsDebuggerPresentDebugBreak"));
                }

                // Marks label.
                if (Labels.ContainsKey(PC))
                {
                    EmitInstructionCountIncrement(false);
                    ILGenerator.MarkLabel(Labels[PC]);
                }

                _EmitCpuInstructionAT(PC);
                PC += 4;
                InstructionsEmitedSinceLastWaypoint++;
            };

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

            // Jumps to the entry point.
            ILGenerator.Emit(OpCodes.Br, Labels[EntryPC]);

            for (PC = MinPC; PC <= MaxPC;)
            {
                uint        CurrentInstructionPC = PC;
                Instruction CurrentInstruction   = InstructionReader[PC];
                InstructionsProcessed++;

                /*
                 * if (!AnalyzedPC.Contains(CurrentInstructionPC))
                 * {
                 *      // Marks label.
                 *      if (Labels.ContainsKey(PC))
                 *      {
                 *              ILGenerator.MarkLabel(Labels[PC]);
                 *      }
                 *
                 *
                 *      PC += 4;
                 *      continue;
                 * }
                 */

                var BranchInfo = GetBranchInfo(CurrentInstruction.Value);

                // Delayed branch instruction.
                if ((BranchInfo & CpuBranchAnalyzer.Flags.BranchOrJumpInstruction) != 0)
                {
                    InstructionsEmitedSinceLastWaypoint += 2;
                    EmitInstructionCountIncrement(true);

                    var BranchAddress = CurrentInstruction.GetBranchAddress(PC);

                    if ((BranchInfo & CpuBranchAnalyzer.Flags.JumpInstruction) != 0)
                    {
                        // Marks label.
                        if (Labels.ContainsKey(PC))
                        {
                            ILGenerator.MarkLabel(Labels[PC]);
                        }

                        _EmitCpuInstructionAT(PC + 4);
                        _EmitCpuInstructionAT(PC + 0);
                        PC += 8;
                    }
                    else
                    {
                        // Branch instruction.
                        EmitCpuInstruction();

                        //if ((BranchInfo & CpuBranchAnalyzer.Flags.Likely) != 0)
                        if (BranchInfo.HasFlag(CpuBranchAnalyzer.Flags.Likely))
                        {
                            //Console.WriteLine("Likely");
                            // Delayed instruction.
                            CpuEmiter._branch_likely(() =>
                            {
                                EmitCpuInstruction();
                            });
                        }
                        else
                        {
                            //Console.WriteLine("Not Likely");
                            // Delayed instruction.
                            EmitCpuInstruction();
                        }

                        if (CurrentInstructionPC + 4 != BranchAddress)
                        {
                            if (Labels.ContainsKey(BranchAddress))
                            {
                                CpuEmiter._branch_post(Labels[BranchAddress]);
                            }
                            // Code not reached.
                            else
                            {
                            }
                        }
                    }
                }
                // Normal instruction.
                else
                {
                    // Syscall instruction.
                    if ((BranchInfo & CpuBranchAnalyzer.Flags.SyscallInstruction) != 0)
                    {
                        StorePC();
                    }
                    EmitCpuInstruction();
                    if ((BranchInfo & CpuBranchAnalyzer.Flags.SyscallInstruction) != 0)
                    {
                        // On this special Syscall
                        if (CurrentInstruction.CODE == FunctionGenerator.NativeCallSyscallCode)
                        {
                            //PC += 4;
                            break;
                        }
                    }
                }
            }


            if (CpuProcessor.PspConfig.ShowInstructionStats)
            {
                Console.Error.WriteLine("-------------------------- {0:X}-{1:X} ", MinPC, MaxPC);
                foreach (var Pair in InstructionStats.OrderByDescending(Item => Item.Value))
                {
                    Console.Error.Write("{0} : {1}", Pair.Key, Pair.Value);
                    if (NewInstruction.ContainsKey(Pair.Key))
                    {
                        Console.Error.Write(" <-- NEW!");
                    }
                    Console.Error.WriteLine("");
                }
            }

            //if (BreakPoint) IsDebuggerPresentDebugBreak();
            Action <CpuThreadState> Delegate = MipsMethodEmiter.CreateDelegate();

            return(Delegate);
        }
示例#4
0
        private Action<CpuThreadState> CreateDelegateForMethodInfo(MethodInfo MethodInfo, HlePspFunctionAttribute HlePspFunctionAttribute)
        {
            var MipsMethodEmiter = new MipsMethodEmiter(CpuProcessor, 0);
            int GprIndex = 4;
            int FprIndex = 0;

            var NotImplementedAttribute = (HlePspNotImplementedAttribute)MethodInfo.GetCustomAttributes(typeof(HlePspNotImplementedAttribute), true).FirstOrDefault();
            bool NotImplementedFunc = (NotImplementedAttribute != null) ? NotImplementedAttribute.Notice : false;
            bool SkipLog = HlePspFunctionAttribute.SkipLog;
            var SafeILGenerator = MipsMethodEmiter.SafeILGenerator;
            SafeILGenerator.Comment("HleModuleHost.CreateDelegateForMethodInfo(" + MethodInfo + ", " + HlePspFunctionAttribute + ")");

            var ParamInfoList = new List<ParamInfo>();

            Action CallAction = () =>
            {
                SafeILGenerator.LoadArgument0CpuThreadState();
                SafeILGenerator.LoadField(typeof(CpuThreadState).GetField("ModuleObject"));
                SafeILGenerator.CastClass(this.GetType());
                foreach (var ParameterInfo in MethodInfo.GetParameters())
                {
                    var ParameterType = ParameterInfo.ParameterType;

                    // The CpuThreadState
                    if (ParameterType == typeof(CpuThreadState))
                    {
                        SafeILGenerator.LoadArgument0CpuThreadState();
                    }
                    // A stringz
                    else if (ParameterType == typeof(string))
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = ParameterType,
                        });
                        SafeILGenerator.LoadArgument0CpuThreadState();
                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        SafeILGenerator.Call(typeof(HleModuleHost).GetMethod("StringFromAddress"));
                        GprIndex++;
                    }
                    // A pointer or ref/out
                    else if (ParameterType.IsPointer || ParameterType.IsByRef)
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = typeof(uint),
                        });
                        MipsMethodEmiter._getmemptr(() =>
                        {
                            MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        }, Safe: true, ErrorDescription: "Invalid Pointer for Argument '" + ParameterType.Name + " " + ParameterInfo.Name + "'");
                        GprIndex++;
                    }
                    /*
                    // An array
                    else if (ParameterType.IsArray)
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = typeof(uint),
                        });
                        // Pointer
                        MipsMethodEmiter._getmemptr(() =>
                        {
                            MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        }, Safe: true, ErrorDescription: "Invalid Pointer for Argument '" + ParameterType.Name + " " + ParameterInfo.Name + "'");
                        GprIndex++;
                        // Array
                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        GprIndex++;
                        MipsMethodEmiter.CallMethod(HleModuleHost.PointerLengthToArrat);
                    }
                    */
                    // A long type
                    else if (ParameterType == typeof(long) || ParameterType == typeof(ulong))
                    {
                        while (GprIndex % 2 != 0) GprIndex++;

                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = ParameterType,
                        });

                        MipsMethodEmiter.LoadGPRLong_Signed(GprIndex + 0);
                        /*
                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex + 0);
                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex + 1);
                        SafeILGenerator.Push((int)32);
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Shl);
                        MipsMethodEmiter.ILGenerator.Emit(OpCodes.Or);
                        */
                        GprIndex += 2;
                    }
                    // A float register.
                    else if (ParameterType == typeof(float))
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Fpr,
                            RegisterIndex = FprIndex,
                            ParameterType = ParameterType,
                        });

                        MipsMethodEmiter.LoadFPR(FprIndex);
                        FprIndex++;
                    }
                    // Test
                    else if (ParameterType == typeof(PspPointer))
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = ParameterType,
                        });

                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        MipsMethodEmiter.CallMethod(typeof(PspPointer).GetMethod("op_Implicit", new[] { typeof(uint) }));
                        GprIndex++;
                    }
                    // An integer register
                    else
                    {
                        ParamInfoList.Add(new ParamInfo()
                        {
                            ParameterName = ParameterInfo.Name,
                            RegisterType = ParamInfo.RegisterTypeEnum.Gpr,
                            RegisterIndex = GprIndex,
                            ParameterType = ParameterType,
                        });

                        MipsMethodEmiter.LoadGPR_Unsigned(GprIndex);
                        GprIndex++;
                    }
                    //MipsMethodEmiter.ILGenerator.Emit(OpCodes.ld
                }
                SafeILGenerator.Call(MethodInfo);
            };

            if (MethodInfo.ReturnType == typeof(void))
            {
                CallAction();
            }
            else if (MethodInfo.ReturnType == typeof(long))
            {
                MipsMethodEmiter.SaveGPRLong(2, CallAction);
            }
            else if (MethodInfo.ReturnType == typeof(float))
            {
                MipsMethodEmiter.SaveFPR(0, CallAction);
            }
            else
            {
                MipsMethodEmiter.SaveGPR(2, CallAction);
            }

            var Delegate = MipsMethodEmiter.CreateDelegate();
            return (CpuThreadState) =>
            {
                bool Trace = (!SkipLog && CpuThreadState.CpuProcessor.PspConfig.DebugSyscalls);
                bool NotImplemented = NotImplementedFunc && CpuThreadState.CpuProcessor.PspConfig.DebugNotImplemented;

                if (Trace && (MethodInfo.DeclaringType.Name == "Kernel_Library")) Trace = false;

                if (NotImplemented)
                {
                    Trace = true;
                    ConsoleUtils.SaveRestoreConsoleState(() =>
                    {
                        Console.ForegroundColor = ConsoleColor.Yellow;
                        Console.WriteLine(
                            "Not implemented {0}.{1}",
                            MethodInfo.DeclaringType.Name, MethodInfo.Name
                        );
                    });
                }

                var Out = Console.Out;
                if (NotImplemented)
                {
                    Out = Console.Error;
                }

                if (Trace)
                {
                    if (ThreadManager.Current != null)
                    {
                        Out.Write(
                            "Thread({0}:'{1}') : RA(0x{2:X})",
                            ThreadManager.Current.Id,
                            ThreadManager.Current.Name,
                            ThreadManager.Current.CpuThreadState.RA
                        );
                    }
                    else
                    {
                        Out.Write("NoThread:");
                    }
                    Out.Write(" : {0}.{1}", MethodInfo.DeclaringType.Name, MethodInfo.Name);
                    Out.Write("(");
                    int Count = 0;
                    foreach (var ParamInfo in ParamInfoList)
                    {
                        if (Count > 0) Out.Write(", ");
                        Out.Write("{0}:", ParamInfo.ParameterName);
                        switch (ParamInfo.RegisterType)
                        {
                            case HleModuleHost.ParamInfo.RegisterTypeEnum.Fpr:
                            case HleModuleHost.ParamInfo.RegisterTypeEnum.Gpr:
                                uint Int4 = (uint)CpuThreadState.GPR[ParamInfo.RegisterIndex];
                                uint Float4 = (uint)CpuThreadState.FPR[ParamInfo.RegisterIndex];
                                Out.Write("{0}", ToNormalizedTypeString(ParamInfo.ParameterType, CpuThreadState, Int4, Float4));
                                break;
                            default:
                                throw (new NotImplementedException());
                        }
                        Count++;
                    }
                    Out.Write(")");
                    //Console.WriteLine("");
                }

                CpuThreadState.ModuleObject = this;
                try
                {
                    Delegate(CpuThreadState);
                }
                catch (MemoryPartitionNoMemoryException)
                {
                    CpuThreadState.GPR[2] = (int)SceKernelErrors.ERROR_ERRNO_NO_MEMORY;
                }
                catch (SceKernelException SceKernelException)
                {
                    CpuThreadState.GPR[2] = (int)SceKernelException.SceKernelError;
                }
                catch (SceKernelSelfStopUnloadModuleException SceKernelSelfStopUnloadModuleException)
                {
                    throw (SceKernelSelfStopUnloadModuleException);
                }
            #if !DO_NOT_PROPAGATE_EXCEPTIONS
                catch (Exception Exception)
                {
                    throw (new Exception(
                        String.Format("ERROR calling {0}.{1}!", MethodInfo.DeclaringType.Name, MethodInfo.Name),
                        Exception
                    ));
                }
            #endif
                finally
                {
                    if (Trace)
                    {
                        Out.WriteLine(" : {0}", ToNormalizedTypeString(MethodInfo.ReturnType, CpuThreadState, (uint)CpuThreadState.GPR[2], (float)CpuThreadState.FPR[0]));
                        Out.WriteLine("");
                    }
                }
            };
        }