private void TestTable(uint[] DefaultSequence, InstructionInfo[] Table) { const string DefaultValue = "!!DEFAULT!!"; var SwitchTree = SwitchGenerator.GenerateSwitchReturnValue<string, InstructionInfo>(Table, (Context) => { if (Context.DecoderReference == null) return ast.Return(ast.Immediate(DefaultValue)); return ast.Return(ast.Immediate(Context.DecoderReference.Name)); }); SwitchTree = (AstNodeStm)(new AstOptimizer().Optimize(SwitchTree)); var SwitchString = GeneratorCSharp.GenerateString<GeneratorCSharp>(SwitchTree); Console.WriteLine(SwitchString); var Func = GeneratorIL.GenerateDelegate<GeneratorIL, Func<SwitchReadWordDelegate, String>>("Decoder", SwitchTree); Func<uint[], string> Decode = (Data) => { var Reader = new Queue<uint>(Data); var Result = Func(() => { if (Reader.Count == 0) return 0x00; return Reader.Dequeue(); }); Assert.AreEqual(0, Reader.Count); return Result; }; foreach (var Item in Table) { var Decoded = Decode(Item.MaskDataVarsList.Select(MaskDataVars => MaskDataVars.Data).ToArray()); Console.WriteLine(Decoded); Assert.AreEqual(Item.Name, Decoded); } Assert.AreEqual(DefaultValue, Decode(DefaultSequence)); }
//static private AstNodeExpr Read8(AstNodeExpr Address) //{ // return ast.CallInstance(GetCpuContext(), (Func<ushort, byte>)CpuContext._NullInstance.ReadMemory1, Address); //} public static AstNodeStm Process(InstructionInfo InstructionInfo, Scope<string, AstLocal> Scope) { var Result = _Process(InstructionInfo, Scope); if (Result == null) return null; return ast.Statements( ast.Assign(GetRegister("Tstates"), GetRegister("Tstates") + InstructionInfo.Tstates), Result ); }
public static List<AstNodeExpr> ParseParameters(InstructionInfo InstructionInfo, Scope<string, AstLocal> Scope) { var Array = new List<AstNodeExpr>(); MatchArgument.Replace(InstructionInfo.Name, (Match) => { var MatchStr = Match.ToString(); switch (MatchStr) { case "%nn": Array.Add( (new AstNodeExprLocal(Scope.Get("%n2")) * 256) | new AstNodeExprLocal(Scope.Get("%n1")) ); break; default: Array.Add(new AstNodeExprLocal(Scope.Get(MatchStr))); break; } return ""; }); return Array; }
public AstNodeStmCpuInstruction(InstructionInfo InstructionInfo, AstNodeStm AstNodeStm) { this.InstructionInfo = InstructionInfo; this.AstNodeStm = AstNodeStm; }
public static AstNodeStm _Process(InstructionInfo InstructionInfo, Scope<string, AstLocal> Scope) { //Mnemonic = Mnemonic.Trim(); //var Parts = Mnemonic.Split(new [] {' ' }, 2); Match Match; var Opcode = InstructionInfo.Name; var Param = InstructionInfo.Format; switch (Opcode) { case "ADC": case "SBC": case "ADD": case "SUB": if ((Match = (GetRegex(@"^(A|HL|IX|IY),(SP|BC|DE|HL|IX|IY|A|B|C|D|E|H|L|IXh|IXl|IYh|IYl|\(HL\)|(\((IX|IY)\+%d\))|%n)$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; var RightRegister = Match.Groups[2].Value; bool withCarry = (new[] { "ADC", "SBC" }).Contains(Opcode); bool isSub = (new[] { "SUB", "SBC" }).Contains(Opcode); MethodInfo doArithmeticMethod; if (LeftRegister == "A") { doArithmeticMethod = ((Func<CpuContext, byte, byte, bool, bool, byte>)Z80InterpreterImplementation.doArithmeticByte).Method; } else { doArithmeticMethod = ((Func<CpuContext, ushort, ushort, bool, bool, ushort>)Z80InterpreterImplementation.doArithmeticWord).Method; } return ast.Assign( GetRegister(LeftRegister), ast.CallStatic(doArithmeticMethod, GetCpuContext(), GetRegister(LeftRegister), ParseRightRegister(RightRegister, Scope), withCarry, isSub) ); } break; case "CP": if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L|IXh|IXl|IYh|IYl)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; return ast.Statements( ast.Statement(ast.CallStatic( (Func<CpuContext, byte, byte, bool, bool, byte>)Z80InterpreterImplementation.doArithmeticByte, GetCpuContext(), GetRegister("A"), GetRegister(Register), false, true )), ast.Statement(ast.CallStatic( (Action<CpuContext, byte>)Z80InterpreterImplementation.adjustFlags, GetCpuContext(), GetRegister(Register) )) ); } if ((Match = (GetRegex(@"^\(HL\)$")).Match(Param)).Success) { return ast.Statement(ast.CallStatic( (Func<CpuContext, byte>)Z80InterpreterImplementation.doCP_HL, GetCpuContext() )); } if ((Match = (GetRegex(@"^(%n)$")).Match(Param)).Success) { return ast.Statements( ast.Assign(GetRegister("A"), ast.CallStatic((Func<CpuContext, byte, byte, bool, bool, byte>)Z80InterpreterImplementation.doArithmeticByte, GetCpuContext(), GetRegister("A"), GetNByte(Scope), false, true)), ast.Statement(ast.CallStatic((Action<CpuContext, byte>)Z80InterpreterImplementation.adjustFlags, GetCpuContext(), GetNByte(Scope))) ); } break; // (RLC|RRC|RL|RR) case "RLC": case "RRC": case "RL": case "RR": { var FuncName = "do" + Opcode; if ((Match = (GetRegex(@"^\(HL\)$")).Match(Param)).Success) { return WriteMemory1( GetRegister("HL"), ast.CallStatic(typeof(Z80InterpreterImplementation).GetMethod(FuncName), GetCpuContext(), true, ReadMemory1(GetRegister("HL"))) ); } if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L|IXh|IXl|IYh|IYl)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; return ast.Assign( GetRegister(Register), ast.CallStatic(typeof(Z80InterpreterImplementation).GetMethod(FuncName), GetCpuContext(), true, GetRegister(Register)) ); } } break; case "RLA": case "RRA": case "RLCA": case "RRCA": if ((Match = (GetRegex(@"^(RL|RR|RLC|RRC)A$")).Match(Opcode)).Success) { var FName = "do" + Match.Groups[1].Value; var doMethod = typeof(Z80InterpreterImplementation).GetMethod(FName); if (doMethod == null) throw (new Exception("Can't find method '" + FName + "'")); return ast.Assign(GetRegister("A"), ast.CallStatic(doMethod, GetCpuContext(), false, GetRegister("A"))); } break; case "AND": case "XOR": case "OR": if ((Match = (GetRegex(@"^(\(HL\)|A|B|C|D|E|H|L|IXh|IXl|IYh|IYl|%n|(\((IX|IY)\+%d\)))$")).Match(Param)).Success) { var RightRegister = Match.Groups[1].Value; //Console.WriteLine("do" + Opcode); return ast.Statement( ast.CallStatic( typeof(Z80InterpreterImplementation).GetMethod("do" + Opcode), GetCpuContext(), ParseRightRegister(RightRegister, Scope) ) ); } break; case "BIT": case "SET": case "RES": if ((Match = (GetRegex(@"^([0-7]),(\(HL\)|A|B|C|D|E|H|L|IXh|IXl|IYh|IYl|%n|(\((IX|IY)\+%d\)))$")).Match(Param)).Success) { var Bit = int.Parse(Match.Groups[1].Value); var RightRegister = Match.Groups[2].Value; //Console.WriteLine("do" + Opcode + ":" + Bit + ":" + RightRegister); return ast.Statement( ast.CallStatic( (Action<CpuContext, int, byte>)Z80InterpreterImplementation.doBIT_r, GetCpuContext(), Bit, ParseRightRegister(RightRegister, Scope) ) ); } break; case "EI": case "DI": return ast.Statement( ast.CallStatic( ((Action<CpuContext, bool>)Z80InterpreterImplementation.EnableDisableInterrupt), GetCpuContext(), (Opcode == "EI") ) ); case "IN": if ((Match = (GetRegex(@"^A,\(%n\)$")).Match(Param)).Success) { return ast.Statement(ast.CallStatic( ((Action<CpuContext, byte>)Z80InterpreterImplementation.doIN), GetCpuContext(), ast.Cast<byte>(ast.Local(Scope.Get("%n"))) )); } break; case "OUT": if ((Match = (GetRegex(@"^\(%n\),A$")).Match(Param)).Success) { return ast.Statement(ast.CallStatic( ((Action<CpuContext, byte>)Z80InterpreterImplementation.doOUT), GetCpuContext(), ast.Cast<byte>(ast.Local(Scope.Get("%n"))) )); } break; case "EX": if ((Match = (GetRegex(@"^DE,HL$")).Match(Param)).Success) { return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doEXDEHL), GetCpuContext())); } if ((Match = (GetRegex(@"^AF,AF'$")).Match(Param)).Success) { return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doEXAFAF_), GetCpuContext())); } break; case "DAA": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doDAA), GetCpuContext())); case "CPL": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doCPL), GetCpuContext())); case "RET": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doRET), GetCpuContext())); case "EXX": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doEXX),GetCpuContext())); case "OTIR": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doOTIR), GetCpuContext())); case "OUTI": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doOUTI), GetCpuContext())); case "LDI": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doLDI), GetCpuContext())); case "LDIR": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doLDIR), GetCpuContext())); case "SCF": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doSCF), GetCpuContext())); case "CCF": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doCCF), GetCpuContext())); case "HALT": return ast.Statement(ast.CallStatic(((Action<CpuContext>)Z80InterpreterImplementation.doHALT), GetCpuContext())); case "DJNZ": if ((Match = (GetRegex(@"^\(PC\+%e\)$")).Match(Param)).Success) { return ast.Statement( ast.CallStatic( ((Action<CpuContext, sbyte>)Z80InterpreterImplementation.doDJNZ), GetCpuContext(), ast.Cast<sbyte>(ast.Local(Scope.Get("%e"))) ) ); } break; case "POP": if ((Match = (GetRegex(@"^(AF|BC|DE|HL|IX|IY)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; return ast.Assign( GetRegister(Register), ast.CallStatic( ((Func<CpuContext, ushort>)Z80InterpreterImplementation.doPop), GetCpuContext() ) ); } break; case "PUSH": if ((Match = (GetRegex(@"^(AF|BC|DE|HL|IX|IY)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; return ast.Statement( ast.CallStatic( ((Action<CpuContext, ushort>)Z80InterpreterImplementation.doPush), GetCpuContext(), GetRegister(Register) ) ); } break; case "INC": case "DEC": { int AddValue = (Opcode == "INC") ? 1 : -1; bool isDec = (Opcode == "DEC"); //(INC|DEC) if ((Match = (GetRegex(@"^\((IX|IY)\+%d\)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; //ctx->tstates += 6; //char off = read8(ctx, ctx->PC++); //byte value = read8(ctx, WR.%2 + off); //write8(ctx, WR.%2 + off, doIncDec(ctx, value, ID_%1)); return WriteMemory1( GetRegister(Register) + GetDByte(Scope), ast.CallStatic( ((Func<CpuContext, byte, bool, byte>)Z80InterpreterImplementation.doIncDec), GetCpuContext(), ReadMemory1(GetRegister(Register) + GetDByte(Scope)), isDec ) ); } if ((Match = (GetRegex(@"^\(HL\)$")).Match(Param)).Success) { //ctx->tstates += 1; //byte value = read8(ctx, WR.HL); //write8(ctx, WR.HL, doIncDec(ctx, value, ID_ % 1)); return WriteMemory1( GetRegister("HL"), ast.CallStatic( ((Func<CpuContext, byte, bool, byte>)Z80InterpreterImplementation.doIncDec), GetCpuContext(), ReadMemory1(GetRegister("HL")), isDec ) ); } if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L|IXh|IXl|IYh|IYl)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; return ast.Assign( GetRegister(Register), ast.CallStatic( ((Func<CpuContext, byte, bool, byte>)Z80InterpreterImplementation.doIncDec), GetCpuContext(), ast.Cast<byte>(GetRegister(Register)), isDec ) ); } if ((Match = (GetRegex(@"^(BC|DE|HL|SP|IX|IY)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; return ast.Assign(GetRegister(Register), ast.Cast<ushort>(GetRegister(Register) + (ushort)AddValue)); } } break; case "IM": if ((Match = (GetRegex(@"^([012])$")).Match(Param)).Success) { var Mode = int.Parse(Match.Groups[1].Value); return ast.Statement( ast.CallStatic( ((Action<CpuContext, byte>)Z80InterpreterImplementation.InterruptMode), GetCpuContext(), ast.Cast<byte>(Mode) ) ); } break; // JumP case "JP": if ((Match = (GetRegex(@"^\((HL|IX|IY)\)$")).Match(Param)).Success) { var Register = Match.Groups[1].Value; //ctx->PC = WR.%1; return ast.Assign(GetRegister("PC"), GetRegister(Register)); } if ((Match = (GetRegex(@"^(C|M|NZ|NC|P|PE|PO|Z)?,?\(%nn\)$")).Match(Param)).Success) { var Flag = Match.Groups[1].Value; return ast.Statement( ast.CallStatic( ((Action<CpuContext, bool, ushort>)Z80InterpreterImplementation.doJUMP), GetCpuContext(), GetFlag(Flag), GetNNWord(Scope) ) ); } break; // Jump Relative case "JR": if ((Match = (GetRegex(@"^(C|NZ|NC|Z)?,?\(PC\+%e\)$")).Match(Param)).Success) { var Flag = Match.Groups[1].Value; return ast.Statement( ast.CallStatic( ((Action<CpuContext, bool, sbyte>)Z80InterpreterImplementation.doJUMP_Inc), GetCpuContext(), GetFlag(Flag), ast.Cast<sbyte>(ast.Local(Scope.Get("%e"))) ) ); } break; case "RST": if ((Match = (GetRegex(@"^(0|8|10|18|20|28|30|38)H$")).Match(Param)).Success) { var PC = Convert.ToInt32(Match.Groups[1].Value, 16); return ast.Statement( ast.CallStatic( ((Action<CpuContext, byte>)Z80InterpreterImplementation.doRST), GetCpuContext(), (byte)PC ) ); } break; case "CALL": if ((Match = (GetRegex(@"^(C|M|NZ|NC|P|PE|PO|Z)?,?\(%nn\)$")).Match(Param)).Success) { var Flag = Match.Groups[1].Value; return ast.Statement( ast.CallStatic( ((Action<CpuContext, bool, ushort>)Z80InterpreterImplementation.doCALL), GetCpuContext(), GetFlag(Flag), GetNNWord(Scope) ) ); //ushort addr = read16(ctx, ctx->PC); //ctx->PC += 2; //if (condition(ctx, C_ % 1)) //{ // ctx->tstates += 1; // doPush(ctx, ctx->PC); // ctx->PC = addr; //} } break; case "NOP": return ast.Statement(); // LOAD case "LD": if ((Match = (GetRegex(@"^\((IX|IY)\+%d\),(A|B|C|D|E|H|L)$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; var RightRegister = Match.Groups[2].Value; return WriteMemory1( GetRegister(LeftRegister) + GetDByte(Scope), GetRegister(RightRegister) ); } if ((Match = (GetRegex(@"^\((IX|IY)\+%d\),%n$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; return WriteMemory1(GetRegister(LeftRegister) + GetDByte(Scope), GetNByte(Scope)); } if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L),(\((IX|IY)\+%d\))$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; var RightRegister = Match.Groups[2].Value; return ast.Assign(GetRegister(LeftRegister), ParseRightRegister(RightRegister, Scope)); } if ((Match = (GetRegex(@"^(BC|DE|HL|SP|IX|IY),\(%nn\)$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; return ast.Assign(GetRegister(LeftRegister), ReadMemory2(GetNNWord(Scope))); } if ((Match = (GetRegex(@"^A,\((BC|DE)\)$")).Match(Param)).Success) { var RightRegister = Match.Groups[1].Value; return ast.Assign(GetRegister("A"), ReadMemory1(GetRegister(RightRegister))); } if ((Match = (GetRegex(@"^\(HL\),%n$")).Match(Param)).Success) { return WriteMemory1(GetRegister("HL"), GetNByte(Scope)); } if ((Match = (GetRegex(@"^\(%nn\),(BC|DE|HL|IX|IY|SP)$")).Match(Param)).Success) { var RightRegister = Match.Groups[1].Value; return WriteMemory2(GetNNWord(Scope), GetRegister(RightRegister)); } if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L),\(%nn\)$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; return ast.Assign(GetRegister(LeftRegister), ast.Cast<byte>(ReadMemory1(GetNNWord(Scope)))); } if ((Match = (GetRegex(@"^\((BC|DE|HL)\),(A|B|C|D|E|H|L)$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; var RightRegister = Match.Groups[2].Value; return WriteMemory1(GetRegister(LeftRegister), GetRegister(RightRegister)); } if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L),\(HL\)$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; return ast.Assign(GetRegister(LeftRegister), ReadMemory1(GetRegister("HL"))); } if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L|IXh|IXl|IYh|IYl),(A|B|C|D|E|H|L|IXh|IXl|IYh|IYl)$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; var RightRegister = Match.Groups[2].Value; return ast.Assign(GetRegister(LeftRegister), GetRegister(RightRegister)); } if ((Match = (GetRegex(@"^(BC|DE|HL|SP|IX|IY),%nn$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; return ast.Statements( ast.Assign( GetRegister(LeftRegister), GetNNWord(Scope) ) ); } if ((Match = (GetRegex(@"^(A|B|C|D|E|H|L|IXh|IXl|IYh|IYl),%n$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; return ast.Statements( ast.Assign( GetRegister(LeftRegister), GetNByte(Scope) ) ); } if ((Match = (GetRegex(@"^\(%nn\),A$")).Match(Param)).Success) { var LeftRegister = Match.Groups[1].Value; return ast.Statements( ast.Statement(ast.CallInstance( GetCpuContext(), ((Action<ushort, byte>)CpuContext._NullInstance.WriteMemory1).Method, GetNNWord(Scope), GetRegister("A") )) ); } if ((Match = (GetRegex(@"^\(HL\),(B|C|D|E|H|L)$")).Match(Param)).Success) { var RightRegister = Match.Groups[1].Value; return ast.Statements( ast.Statement(ast.CallInstance( GetCpuContext(), ((Action<ushort, byte>)CpuContext._NullInstance.WriteMemory1).Method, GetRegister("HL"), GetRegister(RightRegister) )) ); } break; } return null; }