using System; using System.Collections.Generic; using System.Text; using System.IO; namespace Z80_Fetch_Execute { class Program { private class Instruction { public bool IsPrefix = false; public byte Opcode = 0; public string Type = ""; public string Op1 = ""; public string Op2 = ""; public int CC1 = 4; public int CC2 = 0; public string Autocopy = ""; public override string ToString() { if (IsPrefix) { return "(Prefix)"; } else { return ((string)(Type + " " + Op1 + (Op2 == "" ? "" : ", " + Op2)) + (Autocopy == "" ? "" : "\u2192" + Autocopy)).Trim(); } } } private class Table { public ushort Prefix = 0; public Instruction[] Instructions = new Instruction[256]; } private static Dictionary Mirrors = new Dictionary(); static int Main() { string[] Source = Properties.Resources.Table.Split('\n'); Dictionary Tables = new Dictionary(); Table ActiveTable = null; foreach (string Instruction in Source) { string Trimmed = Instruction.Trim(); if (Trimmed == string.Empty || Trimmed[0] == ';') continue; string[] Parts = Trimmed.Split('\t'); if (Parts[0][0] == '!') { ushort Prefix = Convert.ToUInt16(Parts[0].Substring(1), 16); ActiveTable = new Table(); ActiveTable.Prefix = Prefix; Tables.Add(Prefix, ActiveTable); } else { Instruction I = new Instruction(); I.Opcode = Convert.ToByte(Parts[0]); I.Type = Parts.Length < 3 ? "" : Parts[2]; if (I.Type == "") { I = Tables[0].Instructions[I.Opcode]; } else { I.Op1 = Parts.Length < 4 ? "" : Parts[3]; I.Op2 = Parts.Length < 5 ? "" : Parts[4]; I.CC1 = Parts.Length < 6 || Parts[5] == "" ? 0 : Convert.ToInt32(Parts[5]); I.CC2 = Parts.Length < 7 || Parts[6] == "" ? 0 : Convert.ToInt32(Parts[6]); I.Autocopy = Parts.Length < 8 ? "" : Parts[7]; I.IsPrefix = I.Type == "~"; } ActiveTable.Instructions[I.Opcode] = I; if (!Mirrors.ContainsKey(I.ToString())) { Mirrors.Add(I.ToString(), I); } } } AutogenIY(Tables[0xDD], Tables); AutogenIY(Tables[0xDDCB], Tables); StringBuilder TW = new StringBuilder(); /*TW.AppendLine("using System;"); TW.AppendLine("using System.Collections.Generic;"); TW.AppendLine("using System.Text;"); TW.AppendLine("namespace Z80A {"); TW.AppendLine("\tpublic partial class Z80A {"); TW.AppendLine("\t\tpublic void FetchExecute(int cycles) {"); TW.AppendLine("\t\t\t//*"); TW.AppendLine("\t\t\tif (cycles == -1) RunningCycles = 1; else RunningCycles += cycles;"); TW.AppendLine("\t\t\tint ClockCycles = 4;"); TW.AppendLine("\t\t\tsbyte Displacement;"); TW.AppendLine("\t\t\tbyte TB; byte TBH; byte TBL; byte TB1; byte TB2; sbyte TSB; ushort TUS; int TI1; int TI2; int TIR;"); TW.AppendLine("\t\t\twhile (RunningCycles > 0) {"); TW.AppendLine("\t\t\t//Console.Write(\" 0x{0:X4} \", RegPC);"); */ WriteSwitchBlock(TW, Tables[0], 4, Tables, 0); /*TW.AppendLine(); TW.AppendLine("\t\t\tif (flipFlopIFF1 && pinInterrupt) {"); TW.AppendLine("\t\t\t\tswitch (interruptMode) {"); TW.AppendLine("\t\t\t\t\tcase 0:"); TW.AppendLine("\t\t\t\t\t\tbreak;"); TW.AppendLine("\t\t\t\t\tcase 1:"); TW.AppendLine("\t\t\t\t\t\t" + Push("RegPC")); TW.AppendLine("\t\t\t\t\t\tRegPC = 0x38;"); TW.AppendLine("\t\t\t\t\t\tClockCycles += 13;"); TW.AppendLine("\t\t\t\t\t\tbreak;"); TW.AppendLine("\t\t\t\t\tcase 2:"); TW.AppendLine("\t\t\t\t\t\tTUS = (ushort)(RegI * 256 + 0);"); TW.AppendLine("\t\t\t\t\t\t" + Push("RegPC")); TW.AppendLine("\t\t\t\t\t\tRegPC = (ushort)(ReadMemory(TUS++) + 256 * ReadMemory(TUS));"); TW.AppendLine("\t\t\t\t\t\tClockCycles += 19;"); TW.AppendLine("\t\t\t\t\t\tbreak;"); TW.AppendLine("\t\t\t\t}"); TW.AppendLine("\t\t\t\tflipFlopIFF2 = flipFlopIFF1; flipFlopIFF1 = false;"); TW.AppendLine("\t\t\t}"); TW.AppendLine("\t\t\t\tif (cycles == -1) break;"); TW.AppendLine("\t\t\t\tRunningCycles -= ClockCycles;"); TW.AppendLine("\t\t\t}"); TW.AppendLine("\t\t\t//*"); TW.AppendLine("\t\t}"); TW.AppendLine("\t}"); TW.AppendLine("}");*/ string outFile = Properties.Resources.Code.Replace("SWITCH_OF_DOOM();", TW.ToString()); if (File.ReadAllText(@"D:\Documents\Visual Studio 2005\Projects\Z80\Z80A\Fetch Execute.cs") != outFile) File.WriteAllText(@"D:\Documents\Visual Studio 2005\Projects\Z80\Z80A\Fetch Execute.cs", outFile); //} return 0; } static void AutogenIY(Table ixTable, Dictionary tables) { Table TableIY = new Table(); TableIY.Prefix = Convert.ToUInt16(ixTable.Prefix.ToString("X4").Replace("DD", "FD"), 16); foreach (Instruction I in ixTable.Instructions) { Instruction J = new Instruction(); J.Opcode = I.Opcode; J.Op1 = I.Op1.Replace("IX", "IY"); J.Op2 = I.Op2.Replace("IX", "IY"); J.Type = I.Type; J.IsPrefix = I.IsPrefix; J.CC1 = I.CC1; J.CC2 = I.CC2; TableIY.Instructions[I.Opcode] = J; } tables.Add(TableIY.Prefix, TableIY); } static void WriteSwitchBlock(StringBuilder output, Table start, int depth, Dictionary tables, ushort currentPrefix) { string indent = "".PadRight(depth + 2, '\t'); bool FetchedDisplacement = false; if (start.Prefix == 0xDDCB || start.Prefix == 0xFDCB) { FetchedDisplacement = true; output.AppendLine(string.Format("{0}Displacement = (sbyte)ReadMemory(RegPC.Value16++);", indent)); } output.AppendLine("".PadRight(depth, '\t') + "++RegR;"); output.AppendLine("".PadRight(depth, '\t') + "switch (ReadMemory(RegPC.Value16++)) {"); foreach (Instruction I in start.Instructions) { output.AppendLine(string.Format("".PadRight(depth + 1, '\t') + string.Format("case 0x{0:X2}: // {1}", I.Opcode, I))); bool handled = true; if (I.IsPrefix) { ushort newTable = (ushort)(start.Prefix * 256 + I.Opcode); if ((newTable & 0xFF) == 0xED) newTable &= 0xFF; WriteSwitchBlock(output, tables[newTable], depth + 2, tables, start.Prefix); } else { if (I.CC1 == 0 && I.Type != "<-") { I.CC1 = Mirrors[I.ToString()].CC1; if (I.CC1 == 0) throw new Exception(); } output.AppendLine(string.Format("{0}ClockCycles = {1};", indent, I.CC1 < 1 ? 1337 : I.CC1)); output.AppendLine(string.Format("{0}//if (this.Logging) Console.WriteLine(\"0x{{0:X4}}:{{1:X4}} {1}\", RegPC.Value16 - {2}, RegSP.Value16);", indent, I, (depth - 5) / 2 + 1)); if (!FetchedDisplacement && (I.Op1.Contains("+d") || I.Op2.Contains("+d"))) { output.AppendLine(string.Format("{0}Displacement = (sbyte)ReadMemory(RegPC.Value16++);", indent)); } switch (I.Type) { case "NOP": break; case "LD": if (I.Op1 != I.Op2) { if (I.Op1 == "(nn)" && I.Op2.Length == 2) { output.AppendLine(string.Format("{0}TUS = {1};", indent, FetchWord)); output.AppendLine(string.Format("{0}WriteMemory(TUS++, Reg{1}.Low8);", indent, I.Op2)); output.AppendLine(string.Format("{0}WriteMemory(TUS, Reg{1}.High8);", indent, I.Op2)); } else if (I.Op2 == "(nn)" && I.Op1.Length == 2) { output.AppendLine(string.Format("{0}TUS = {1};", indent, FetchWord)); output.AppendLine(string.Format("{0}Reg{1}.Low8 = ReadMemory(TUS++); Reg{1}.High8 = ReadMemory(TUS);", indent, I.Op1)); } else { bool paren; string op1 = SetRegisterName(I.Op1, out paren); string op2 = GetRegisterName(I.Op2); if (paren) { output.AppendLine(string.Format("{0}{1}{2});", indent, op1, op2)); } else { output.AppendLine(string.Format("{0}{1} = {2};", indent, op1, op2)); } } } break; case "JP": if (I.Op2 == "") { output.AppendLine(string.Format("{0}RegPC.Value16 = {1};", indent, GetRegisterName(I.Op1))); } else { output.AppendLine(string.Format("{0}TUS = {1};", indent, GetRegisterName(I.Op2))); output.AppendLine(string.Format("{0}if ({1}) {{", indent, GetFlagTest(I.Op1))); output.AppendLine(string.Format("{0}\tRegPC.Value16 = TUS;", indent)); output.AppendLine(string.Format("{0}}} else {{", indent)); output.AppendLine(string.Format("{0}\tClockCycles = {1};", indent, I.CC2)); output.AppendLine(string.Format("{0}}}", indent)); } break; case "CALL": if (I.Op2 == "") { output.AppendLine(string.Format("{0}TUS = {1};", indent, GetRegisterName(I.Op1))); output.AppendLine(string.Format("{0}{1}", indent, Push("RegPC"))); output.AppendLine(string.Format("{0}RegPC.Value16 = TUS;", indent)); } else { output.AppendLine(string.Format("{0}TUS = {1};", indent, GetRegisterName(I.Op2))); output.AppendLine(string.Format("{0}if ({1}) {{", indent, GetFlagTest(I.Op1))); output.AppendLine(string.Format("{0}\t{1}", indent, Push("RegPC"))); output.AppendLine(string.Format("{0}\tRegPC.Value16 = TUS;", indent)); output.AppendLine(string.Format("{0}}} else {{", indent)); output.AppendLine(string.Format("{0}\tClockCycles = {1};", indent, I.CC2)); output.AppendLine(string.Format("{0}}}", indent)); } break; case "RET": case "RETI": case "RETN": //output.AppendLine(string.Format("{0}CanInt = true;", indent)); if (I.Op1 == "") { output.AppendLine(string.Format("{0}{1}", indent, Pop("RegPC"))); } else { output.AppendLine(string.Format("{0}if ({1}) {{", indent, GetFlagTest(I.Op1))); output.AppendLine(string.Format("{0}\t{1}", indent, Pop("RegPC"))); output.AppendLine(string.Format("{0}}} else {{", indent)); output.AppendLine(string.Format("{0}\tClockCycles = {1};", indent, I.CC2)); output.AppendLine(string.Format("{0}}}", indent)); } break; case "PUSH": output.AppendLine(string.Format("{0}{1}", indent, Push("Reg" + I.Op1))); break; case "POP": output.AppendLine(string.Format("{0}{1}", indent, Pop("Reg" + I.Op1))); break; case "RST": output.AppendLine(string.Format("{0}{1}", indent, Push("RegPC"))); output.AppendLine(string.Format("{0}RegPC.Value16 = 0x{1};", indent, I.Op1.Substring(1))); break; case "JR": output.AppendLine(string.Format("{0}TSB = (sbyte)ReadMemory(RegPC.Value16++);", indent)); if (I.Op2 == "") { output.AppendLine(string.Format("{0}RegPC.Value16 = (ushort)(RegPC.Value16 + TSB);", indent)); } else { output.AppendLine(string.Format("{0}if ({1}) {{", indent, GetFlagTest(I.Op1))); output.AppendLine(string.Format("{0}\tRegPC.Value16 = (ushort)(RegPC.Value16 + TSB);", indent)); output.AppendLine(string.Format("{0}}} else {{", indent)); output.AppendLine(string.Format("{0}\tClockCycles = {1};", indent, I.CC2)); output.AppendLine(string.Format("{0}}}", indent)); } break; case "DJNZ": output.AppendLine(string.Format("{0}TSB = (sbyte)ReadMemory(RegPC.Value16++);", indent)); output.AppendLine(string.Format("{0}if (--RegBC.High8 != 0) {{", indent)); output.AppendLine(string.Format("{0}\tRegPC.Value16 = (ushort)(RegPC.Value16 + TSB);", indent)); output.AppendLine(string.Format("{0}}} else {{", indent)); output.AppendLine(string.Format("{0}\tClockCycles = {1};", indent, I.CC2)); output.AppendLine(string.Format("{0}}}", indent)); break; case "DI": output.AppendLine(string.Format("{0}flipFlopIFF1 = false;", indent)); output.AppendLine(string.Format("{0}flipFlopIFF2 = false;", indent)); break; case "EI": /*output.AppendLine(string.Format("{0}flipFlopIFF1 = true;", indent)); output.AppendLine(string.Format("{0}flipFlopIFF2 = true;", indent));*/ output.AppendLine(string.Format("{0}PendingEI = true;", indent)); break; case "IM": output.AppendLine(string.Format("{0}interruptMode = {1};", indent, I.Op1.Substring(1))); break; case "LDI": case "CPI": case "INI": case "OUTI": case "LDD": case "CPD": case "IND": case "OUTD": case "LDIR": case "CPIR": case "INIR": case "OTIR": case "LDDR": case "CPDR": case "INDR": case "OTDR": string ExtraCondition = ""; char Direction = I.Type[I.Type.Length - 1]; bool Repeat = Direction == 'R'; if (Repeat) Direction = I.Type[I.Type.Length - 2]; string Incrementer = Direction == 'I' ? "++" : "--"; switch (I.Type[0]) { case 'L': output.AppendLine(string.Format("{0}WriteMemory(RegDE.Value16{1}, ReadMemory(RegHL.Value16{1}));", indent, Incrementer)); break; case 'C': output.AppendLine(string.Format("{0}TB1 = ReadMemory(RegHL.Value16{1}); TB2 = (byte)(RegAF.High8 - TB1);", indent, Incrementer)); output.AppendLine(string.Format("{0}RegFlagN = true;", indent)); output.AppendLine(string.Format("{0}RegFlagH = TableHalfBorrow[RegAF.High8, TB1];", indent)); output.AppendLine(string.Format("{0}RegFlagZ = TB2 == 0;", indent)); output.AppendLine(string.Format("{0}RegFlagS = TB2 > 127;", indent)); ExtraCondition = " && !RegFlagZ"; break; case 'I': output.AppendLine(string.Format("{0}WriteMemory(RegHL.Value16{1}, ReadHardware(RegBC.Value16));", indent, Incrementer)); break; case 'O': output.AppendLine(string.Format("{0}WriteHardware(RegBC.Value16, ReadMemory(RegHL.Value16{1}));", indent, Incrementer)); break; } string Decrementer = (I.Type[0] == 'L' || I.Type[0] == 'C') ? "BC.Value16" : "BC.High8"; output.AppendLine(string.Format("{0}--Reg{1};", indent, Decrementer)); switch (I.Type[0]) { case 'L': case 'C': output.AppendLine(string.Format("{0}RegFlagP = RegBC.Value16 != 0;", indent)); break; case 'O': case 'I': output.AppendLine(string.Format("{0}RegFlagZ = RegBC.High8 == 0;", indent)); output.AppendLine(string.Format("{0}RegFlagN = true;", indent)); break; } switch (I.Type[0]) { case 'L': output.AppendLine(string.Format("{0}RegFlagH = false;", indent)); output.AppendLine(string.Format("{0}RegFlagN = false;", indent)); break; } if (Repeat) { output.AppendLine(string.Format("{0}if (Reg{1} != 0{2}) {{", indent, Decrementer, ExtraCondition)); output.AppendLine(string.Format("{0}\tRegPC.Value16 -= 2;", indent, Decrementer)); output.AppendLine(string.Format("{0}}} else {{", indent)); output.AppendLine(string.Format("{0}\tClockCycles = {1};", indent, I.CC2)); output.AppendLine(string.Format("{0}}}", indent)); } break; case "OUT": output.AppendLine(string.Format("{0}WriteHardware({1}, {2});", indent, GetRegisterName(I.Op1), GetRegisterName(I.Op2))); break; case "ADD": case "ADC": case "SUB": case "SBC": case "AND": case "XOR": case "OR": case "CP": if (I.Op1 == "HL" || I.Op1 == "IX" || I.Op1 == "IY") { string RegName = GetRegisterName(I.Op1); switch (I.Type) { case "ADD": case "ADC": output.AppendLine(string.Format("{0}TI1 = (short){2}; TI2 = (short){1}; TIR = TI1 + TI2;", indent, GetRegisterName(I.Op2), RegName)); if (I.Type == "ADC") output.AppendLine(string.Format("{0}if (RegFlagC) {{ ++TIR; ++TI2; }}", indent)); output.AppendLine(string.Format("{0}TUS = (ushort)TIR;", indent)); output.AppendLine(string.Format("{0}RegFlagH = ((TI1 & 0xFFF) + (TI2 & 0xFFF)) > 0xFFF;", indent)); output.AppendLine(string.Format("{0}RegFlagN = false;", indent)); output.AppendLine(string.Format("{0}RegFlagC = ((ushort)TI1 + (ushort)TI2) > 0xFFFF;", indent)); if (I.Type == "ADC") { output.AppendLine(string.Format("{0}RegFlagP = TIR > 32767 || TIR < -32768;", indent)); output.AppendLine(string.Format("{0}RegFlagS = TUS > 32767;", indent)); output.AppendLine(string.Format("{0}RegFlagZ = TUS == 0;", indent)); } output.AppendLine(string.Format("{0}{1} = TUS;", indent, RegName)); break; case "SBC": output.AppendLine(string.Format("{0}TI1 = (short){2}; TI2 = (short){1}; TIR = TI1 - TI2;", indent, GetRegisterName(I.Op2), RegName)); output.AppendLine(string.Format("{0}if (RegFlagC) {{ --TIR; ++TI2; }}", indent)); output.AppendLine(string.Format("{0}TUS = (ushort)TIR;", indent)); output.AppendLine(string.Format("{0}RegFlagH = ((TI1 & 0xFFF) - (TI2 & 0xFFF)) < 0;", indent)); output.AppendLine(string.Format("{0}RegFlagN = true;", indent)); output.AppendLine(string.Format("{0}RegFlagC = ((ushort)TI1 - (ushort)TI2) < 0;", indent)); output.AppendLine(string.Format("{0}RegFlagP = TIR > 32767 || TIR < -32768;", indent)); output.AppendLine(string.Format("{0}RegFlagS = TUS > 32767;", indent)); output.AppendLine(string.Format("{0}RegFlagZ = TUS == 0;", indent)); output.AppendLine(string.Format("{0}{1} = TUS;", indent, RegName)); break; default: output.AppendLine(string.Format("{0}throw new Exception(\"Unsupported instruction.\");", indent)); handled = false; break; } } else { int index = 0; switch (I.Type) { case "ADD": index = 0; break; case "ADC": index = 1; break; case "SUB": index = 2; break; case "SBC": index = 3; break; case "AND": index = 4; break; case "XOR": index = 5; break; case "OR": index = 6; break; case "CP": index = 7; break; } string op1 = "RegAF.High8"; string op2 = ""; if (I.Op2 == "") { op2 = GetRegisterName(I.Op1); } else { op1 = GetRegisterName(I.Op1); op2 = GetRegisterName(I.Op2); } output.AppendLine(string.Format("{0}RegAF.Value16 = TableALU[{1}, {2}, {3}, {4}];", indent, index, op1, op2, I.Type[I.Type.Length - 1] == 'C' ? "RegFlagC ? 1 : 0" : "0")); } break; case "INC": case "DEC": string OpName = I.Type[0] + I.Type.Substring(1).ToLower(); string OpDirection = I.Type == "INC" ? "++" : "--"; if (I.Op1.Length == 2) { output.AppendLine(string.Format("{0}{1}{2};", indent, OpDirection, GetRegisterName(I.Op1))); } else { bool np; string RS = SetRegisterName(I.Op1, out np); if (!np) { output.AppendLine(string.Format("{0}RegAF.Low8 = (byte)(Table{1}[{2}{3}] | (RegAF.Low8 & 1));", indent, OpName, OpDirection, RS)); } else { string RG = GetRegisterName(I.Op1); output.AppendLine(string.Format("{0}TB = {1}; RegAF.Low8 = (byte)(Table{2}[{3}TB] | (RegAF.Low8 & 1)); {4}TB);", indent, RG, OpName, OpDirection, RS)); } } break; case "EX": if (I.Op1 != "(SP)") { output.AppendLine(string.Format("{0}TUS = {1}; {1} = {2}; {2} = TUS;", indent, GetRegisterName(I.Op1), GetRegisterName(I.Op2))); } else { output.AppendLine(string.Format("{0}TUS = RegSP.Value16; TBL = ReadMemory(TUS++); TBH = ReadMemory(TUS--);", indent)); output.AppendLine(string.Format("{0}WriteMemory(TUS++, {1}); WriteMemory(TUS, {2});", indent, GetRegisterName(LowerBytePair(I.Op2)), GetRegisterName(UpperBytePair(I.Op2)))); output.AppendLine(string.Format("{0}Reg{1} = TBL; Reg{2} = TBH;", indent, LowerBytePair(I.Op2), UpperBytePair(I.Op2))); } break; case "RLCA": output.AppendLine(string.Format("{0}RegAF.Value16 = TableRotShift[0, 0, RegAF.Value16];", indent)); break; case "RRCA": output.AppendLine(string.Format("{0}RegAF.Value16 = TableRotShift[0, 1, RegAF.Value16];", indent)); break; case "RLA": output.AppendLine(string.Format("{0}RegAF.Value16 = TableRotShift[0, 2, RegAF.Value16];", indent)); break; case "RRA": output.AppendLine(string.Format("{0}RegAF.Value16 = TableRotShift[0, 3, RegAF.Value16];", indent)); break; case "RLC": case "RRC": case "RL": case "RR": case "SLA": case "SRA": case "SL1": case "SRL": output.AppendLine(string.Format("{0}TUS = TableRotShift[1, {1}, RegAF.Low8 + 256 * {2}];", indent, (I.Type[0] == 'R' ? 0 : 4) + (I.Type[1] == 'L' ? 0 : 1) + ((I.Type[0] == 'R' && I.Type.Length == 3 || I.Type[0] == 'S' && I.Type[2] == 'A') ? 0 : 2), GetRegisterName(I.Op1))); bool needsParens; string writeBack = SetRegisterName(I.Op1, out needsParens); if (needsParens) { output.AppendLine(string.Format("{0}{1}(byte)(TUS >> 8));", indent, writeBack)); } else { output.AppendLine(string.Format("{0}{1} = (byte)(TUS >> 8);", indent, writeBack)); } output.AppendLine(string.Format("{0}RegAF.Low8 = (byte)TUS;", indent, writeBack)); if (I.Autocopy != "") output.AppendLine(string.Format("{0}{1} = (byte)TUS;", indent, GetRegisterName(I.Autocopy))); break; case "RES": case "SET": char Action = I.Type[0] == 'R' ? '&' : '|'; string Amount = string.Format("0x{0:X2}", (1 << Convert.ToInt32(I.Op1))); if (Action == '&') Amount = '~' + Amount; Amount = "unchecked((byte)" + Amount + ")"; writeBack = SetRegisterName(I.Op2, out needsParens); if (I.Autocopy != "") { bool dud; output.AppendLine(string.Format("{0}{1} = (byte)({2} {3} {4});", indent, SetRegisterName(I.Autocopy, out dud), GetRegisterName(I.Op2), Action, Amount)); if (needsParens) { output.AppendLine(string.Format("{0}{1}{2});", indent, writeBack, GetRegisterName(I.Autocopy))); } else { output.AppendLine(string.Format("{0}{1} = {2};", indent, writeBack, GetRegisterName(I.Autocopy))); } } else { if (needsParens) { output.AppendLine(string.Format("{0}{1}(byte)({2} {3} {4}));", indent, writeBack, GetRegisterName(I.Op2), Action, Amount)); } else { output.AppendLine(string.Format("{0}{1} {2}= {3};", indent, writeBack, Action, Amount)); } } break; case "BIT": output.AppendLine(string.Format("{0}RegFlagZ = ({1} & 0x{2:X2}) == 0;", indent, GetRegisterName(I.Op2), 1 << Convert.ToInt32(I.Op1))); output.AppendLine(string.Format("{0}RegFlagP = RegFlagZ;", indent)); if (I.Op1 == "7") { output.AppendLine(string.Format("{0}RegFlagS = !RegFlagZ;", indent)); } else { output.AppendLine(string.Format("{0}RegFlagS = false;", indent)); } output.AppendLine(string.Format("{0}RegFlagH = true;", indent)); output.AppendLine(string.Format("{0}RegFlagN = false;", indent)); break; case "NEG": output.AppendLine(string.Format("{0}RegAF.Value16 = TableNeg[RegAF.Value16];", indent)); break; case "DAA": output.AppendLine(string.Format("{0}RegAF.Value16 = TableDaa[RegAF.Value16];", indent)); break; case "CPL": output.AppendLine(string.Format("{0}RegAF.High8 ^= 0xFF; RegFlagH = true; RegFlagN = true;", indent)); break; case "SCF": output.AppendLine(string.Format("{0}RegFlagH = false; RegFlagN = false; RegFlagC = true;", indent)); break; case "CCF": output.AppendLine(string.Format("{0}RegFlagH = RegFlagC; RegFlagN = false; RegFlagC ^= true;", indent)); break; case "RRD": case "RLD": output.AppendLine(string.Format("{0}TB1 = RegAF.High8; TB2 = ReadMemory(RegHL.Value16);", indent)); if (I.Type[1] == 'R') { output.AppendLine(string.Format("{0}WriteMemory(RegHL.Value16, (byte)((TB2 >> 4) + (TB1 << 4)));", indent)); output.AppendLine(string.Format("{0}RegAF.High8 = (byte)((TB1 & 0xF0) + (TB2 & 0x0F));", indent)); } else { output.AppendLine(string.Format("{0}WriteMemory(RegHL.Value16, (byte)((TB1 & 0x0F) + (TB2 << 4)));", indent)); output.AppendLine(string.Format("{0}RegAF.High8 = (byte)((TB1 & 0xF0) + (TB2 >> 4));", indent)); } output.AppendLine(string.Format("{0}RegFlagS = RegAF.High8 > 127;", indent)); output.AppendLine(string.Format("{0}RegFlagZ = RegAF.High8 == 0;", indent)); output.AppendLine(string.Format("{0}RegFlagH = false;", indent)); output.AppendLine(string.Format("{0}RegFlagP = TableParity[RegAF.High8];", indent)); output.AppendLine(string.Format("{0}RegFlagN = false;", indent)); break; case "IN": if (I.Op2 != "C") { output.AppendLine(string.Format("{0}RegAF.High8 = ReadHardware((ushort){1});", indent, GetRegisterName(I.Op2))); } else { writeBack = I.Op1 == "0" ? "TB" : GetRegisterName(I.Op1); output.AppendLine(string.Format("{0}{2} = ReadHardware((ushort){1});", indent, GetRegisterName(I.Op2), writeBack)); output.AppendLine(string.Format("{0}RegFlagS = {1} > 127;", indent, writeBack)); output.AppendLine(string.Format("{0}RegFlagZ = {1} == 0;", indent, writeBack)); output.AppendLine(string.Format("{0}RegFlagH = false;", indent, writeBack)); output.AppendLine(string.Format("{0}RegFlagP = TableParity[{1}];", indent, writeBack)); output.AppendLine(string.Format("{0}RegFlagN = false;", indent, writeBack)); } break; case "EXX": output.AppendLine(string.Format("{0}TUS = RegBC.Value16; RegBC.Value16 = RegAltBC.Value16; RegAltBC.Value16 = TUS;", indent)); output.AppendLine(string.Format("{0}TUS = RegDE.Value16; RegDE.Value16 = RegAltDE.Value16; RegAltDE.Value16 = TUS;", indent)); output.AppendLine(string.Format("{0}TUS = RegHL.Value16; RegHL.Value16 = RegAltHL.Value16; RegAltHL.Value16 = TUS;", indent)); break; case "HALT": output.AppendLine(string.Format("{0}if (!(flipFlopIFF1 && pinInterrupt)) --RegPC.Value16;", indent)); break; case "<-": output.AppendLine(string.Format("{0}// Invalid sequence.", indent)); break; default: output.AppendLine(string.Format("{0}throw new Exception(\"Unsupported instruction.\");", indent)); handled = false; break; } } if (handled) output.AppendLine("".PadRight(depth + 2, '\t') + "break;"); } output.AppendLine("".PadRight(depth, '\t') + "}"); } static string GetFlagTest(string flag) { char Flag = 'F'; bool Inequality = true; switch (flag) { case "C": Flag = 'C'; Inequality = false; break; case "NC": Flag = 'C'; Inequality = true; break; case "PE": Flag = 'P'; Inequality = false; break; case "PO": Flag = 'P'; Inequality = true; break; case "Z": Flag = 'Z'; Inequality = false; break; case "NZ": Flag = 'Z'; Inequality = true; break; case "M": Flag = 'S'; Inequality = false; break; case "P": Flag = 'S'; Inequality = true; break; } return (Inequality ? "!" : "") + "RegFlag" + Flag; } /*/ static string Push(string reg) { return "WriteMemory(--RegSP.Value16, " + LowerBytePair(reg) + "); WriteMemory(--RegSP.Value16, " + UpperBytePair(reg) + ");"; } static string Pop(string reg) { return UpperBytePair(reg) + " = ReadMemory(RegSP.Value16++); " + LowerBytePair(reg) + " = ReadMemory(RegSP.Value16++);"; } /*/ static string Push(string reg) { return "WriteMemory(--RegSP.Value16, " + UpperBytePair(reg) + "); WriteMemory(--RegSP.Value16, " + LowerBytePair(reg) + ");"; } static string Pop(string reg) { return LowerBytePair(reg) + " = ReadMemory(RegSP.Value16++); " + UpperBytePair(reg) + " = ReadMemory(RegSP.Value16++);"; } //*/ static string FetchByte = "ReadMemory(RegPC.Value16++)"; static string FetchWord = "(ushort)(ReadMemory(RegPC.Value16++) + ReadMemory(RegPC.Value16++) * 256)"; static string GetSetRegisterName(bool setting, string def, out bool needsParen) { needsParen = false; switch (def) { case "n": return FetchByte; case "nn": return FetchWord; case "(nn)": if (setting) { needsParen = true; return "WriteMemory(" + FetchWord + ", "; } else { return "ReadMemory(" + FetchWord + ")"; } case "0": return "0"; } string reg = def; if (def[0] == '(') { reg = reg.Substring(1, reg.Length - 2); } if (reg[reg.Length - 1] == '\'') reg = "Alt" + reg.Substring(0, reg.Length - 1) + ".Value16"; if (reg == "IX+d" || reg == "IY+d") { reg = "(ushort)(Reg" + reg.Replace("+d", ".Value16 + Displacement)"); } else if (reg == "R" && !setting) { reg = "(byte)(RegR & 0x7F)"; } else { switch (reg) { case "A": reg = "AF.High8"; break; case "F": reg = "AF.Low8"; break; case "AF": reg = "AF.Value16"; break; case "B": reg = "BC.High8"; break; case "C": reg = "BC.Low8"; break; case "BC": reg = "BC.Value16"; break; case "D": reg = "DE.High8"; break; case "E": reg = "DE.Low8"; break; case "DE": reg = "DE.Value16"; break; case "H": reg = "HL.High8"; break; case "L": reg = "HL.Low8"; break; case "HL": reg = "HL.Value16"; break; case "IXH": reg = "IX.High8"; break; case "IXL": reg = "IX.Low8"; break; case "IX": reg = "IX.Value16"; break; case "IYH": reg = "IY.High8"; break; case "IYL": reg = "IY.Low8"; break; case "IY": reg = "IY.Value16"; break; case "PC": reg = "PC.Value16"; break; case "SP": reg = "SP.Value16"; break; } reg = "Reg" + reg; } if (def[0] == '(') { if (setting) { needsParen = true; reg = "WriteMemory(" + reg + ", "; } else { reg = "ReadMemory(" + reg + ")"; } } return reg; } static string GetRegisterName(string def) { bool b; return GetSetRegisterName(false, def, out b); } static string UpperBytePair(string def) { return def + ".High8"; } static string LowerBytePair(string def) { return def + ".Low8"; } static string SetRegisterName(string def, out bool needsParen) { return GetSetRegisterName(true, def, out needsParen); } } }