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]) ); }
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]) ); }