static public DynarecResult SE_n(DynarecContextChip8 Context, byte X, byte Byte)
		{
			return ast.IfElse(
				ast.Binary(Context.GetRegister(X), "==", Byte),
				ast.GotoAlways(Context.PCToLabel[Context.EndPC + 2])
			);
		}
		static public DynarecResult RET(DynarecContextChip8 Context)
		{
			return ast.Statements(
#if !NATIVE_CALLS
				ast.Assign(Context.GetPC(), ast.Cast<ushort>(ast.CallInstance(Context.GetCallStack(), (Func<uint>)((new Stack<uint>()).Pop)))),
#endif
ast.Return()
			);
		}
		static public DynarecResult JP_addr(DynarecContextChip8 Context, ushort Address)
		{
			return ast.Statements(
#if NATIVE_JUMPS
				ast.Statement(ast.CallTail(ast.CallDelegate(Context.GetCallForAddress(Address + Context.GetRegister(0)), Context.GetCpuContext()))),
#else
				ast.Statements(ast.Assign(Context.GetPC(), Address + Context.GetRegister(0))),
#endif
 ast.Return()
			);
		}
		static public DynarecResult CALL(DynarecContextChip8 Context, ushort Address)
		{
			return ast.Statements(
#if NATIVE_CALLS
				ast.Statement(ast.CallDelegate(Context.GetCallForAddress(Address), Context.GetCpuContext()))
#else
				ast.Statement(ast.CallInstance(Context.GetCallStack(), (Action<uint>)((new Stack<uint>()).Push), Context.EndPC)),
				ast.Statements(ast.Assign(Context.GetPC(), Address)),
				ast.Return()
#endif
			);
		}
		static public DynarecResult LD_vx_Iptr(DynarecContextChip8 Context, byte X)
		{
			return ast.Statement(ast.CallStatic((Action<CpuContext, byte>)Chip8InterpreterImplementation.LD_vx_Iptr, Context.GetCpuContext(), X));
		}
		static public DynarecResult INVALID(DynarecContextChip8 Context)
		{
			return ast.Throw(ast.New<Exception>("Invalid instruction!"));
		}
		static public DynarecResult ADD_i_vx(DynarecContextChip8 Context, byte X)
		{
			return ast.Assign(Context.GetI(), Context.GetI() + Context.GetRegister(X));
		}
		static public DynarecResult LD_f_vx(DynarecContextChip8 Context, byte X)
		{
			return ast.Assign(Context.GetI(), ast.Cast<ushort>(ast.Cast<int>(Context.GetRegister(X)) * ast.Cast<int>(5)));
		}
		static public DynarecResult LD_vx_dt(DynarecContextChip8 Context, byte X)
		{
			return ast.Assign(Context.GetRegister(X), Context.GetDelayTimerValue());
		}
		static public DynarecResult LD_st_vx(DynarecContextChip8 Context, byte X)
		{
			return ast.Assign(Context.GetSoundTimerValue(), Context.GetRegister(X));
		}
		static public DynarecResult LD_v(DynarecContextChip8 Context, byte X, byte Y)
		{
			return ast.Assign(Context.GetRegister(X), Context.GetRegister(Y));
		}
		static public DynarecResult ADD_n(DynarecContextChip8 Context, byte X, byte Byte)
		{
			return _ADD(Context, X, Byte);
			//Context.V[X] += Byte;
		}
		static public DynarecResult LD_addr(DynarecContextChip8 Context, ushort Address)
		{
			return ast.Assign(Context.GetI(), Address);
		}
		static private DynarecResult _SUB(DynarecContextChip8 Context, byte X, AstNodeExpr Value)
		{
			return ast.Statements(
				ast.Assign(Context.GetRegister(15), ast.Cast<byte>(ast.Binary(ast.Cast<uint>(Context.GetRegister(X)), ">", ast.Cast<uint>(Value)))),
				ast.Assign(Context.GetRegister(X), Context.GetRegister(X) - Value)
			);
		}
		static public DynarecResult SHL(DynarecContextChip8 Context, byte X, byte Y) { return _BinaryOp(Context, X, "<<", Y); }
		static public DynarecResult SUBN(DynarecContextChip8 Context, byte X, byte Y) { throw (new NotImplementedException()); }
		static public DynarecResult SUB(DynarecContextChip8 Context, byte X, byte Y) { return _SUB(Context, X, Context.GetRegister(Y)); }
		//static public DynarecResult SYS(DynarecContext DynarecContext, ushort Address)
		//{
		//	return ast.Statement();
		//}

		static public DynarecResult CLS(DynarecContextChip8 Context)
		{
			return ast.Statement(ast.CallStatic((Action<CpuContext>)Chip8InterpreterImplementation.CLS, Context.GetCpuContext()));
		}
		static public DynarecResult LD_n(DynarecContextChip8 Context, byte X, byte Byte)
		{
			return ast.Assign(Context.GetRegister(X), ast.Immediate(Byte));
		}
		static public DynarecResult RND(DynarecContextChip8 Context, byte X, byte Byte)
		{
			return ast.Statement(ast.CallStatic((Action<CpuContext, byte, byte>)Chip8InterpreterImplementation.RND, Context.GetCpuContext(), X, Byte));
		}
		static private DynarecResult _BinaryOp(DynarecContextChip8 Context, byte X, string Op, byte Y)
		{
			return ast.Assign(Context.GetRegister(X), ast.Binary(Context.GetRegister(X), Op, Context.GetRegister(Y)));
		}
		static public DynarecResult DRW(DynarecContextChip8 Context, byte X, byte Y, byte Nibble)
		{
			return ast.Statement(ast.CallStatic((Action<CpuContext, byte, byte, byte>)Chip8InterpreterImplementation.DRW, Context.GetCpuContext(), X, Y, Nibble));
		}
		static public DynarecResult SKNP(DynarecContextChip8 Context, byte X)
		{
			return ast.IfElse(
				ast.Unary("!", ast.CallInstance(
					Context.GetController(),
					typeof(IController).GetMethod("IsPressed"),
					Context.GetRegister(X)
				)),
				ast.GotoAlways(Context.PCToLabel[Context.EndPC + 2])
			);
		}
Пример #24
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();
        }
		static public DynarecResult SNE_v(DynarecContextChip8 Context, byte X, byte Y)
		{
			return ast.IfElse(
				ast.Binary(Context.GetRegister(X), "!=", Context.GetRegister(Y)),
				ast.GotoAlways(Context.PCToLabel[Context.EndPC + 2])
			);
		}