public void ExecuteOne() { Cycle++; var opcodePos = Reg.ProgramCounter; var opcode = (OpCode)_memory[Reg.ProgramCounter++]; var action = _opcodes[(int)opcode]; if (action.Action == null) { throw new Exception($"Unknown opcode: ${(int)opcode:X} ({opcode}) at pos ${opcodePos:X} ({opcodePos})"); } #region OPCODE_DEBUGGING CurrentExecutingOpcode = new CurrentExecutingOpcodeStruct(); CurrentExecutingOpcode.RegBefore = Reg; CurrentExecutingOpcode.PC = (Word)opcodePos; CurrentExecutingOpcode.Opcode = opcode; if (Reg.ProgramCounter < _memory.Length) { CurrentExecutingOpcode.B1 = _memory[Reg.ProgramCounter]; } if (Reg.ProgramCounter + 1 < _memory.Length) { CurrentExecutingOpcode.B2 = _memory[Reg.ProgramCounter + 1]; } #endregion try { action.Action.Invoke(); DebugPrintOpcode(CurrentExecutingOpcode); } catch (Exception exception) { DebugPrintOpcode(CurrentExecutingOpcode); throw; } }
private void DebugPrintOpcode(CurrentExecutingOpcodeStruct ceo) { string addr; var word = false; switch (ceo.MemoryAccessType) { case MemoryAccessType.None: addr = "".PadRight(10, ' ') + "; "; break; case MemoryAccessType.Immediate: addr = ("#" + ceo.Data.ToString("X2")).PadRight(10, ' ') + "; "; break; case MemoryAccessType.Abs: addr = ("$" + ceo.Address.ToString("X4")).PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); word = true; break; case MemoryAccessType.AbsX: addr = ("$" + ceo.Address.ToString("X4") + ",X").PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); word = true; break; case MemoryAccessType.AbsY: addr = ("$" + ceo.Address.ToString("X4") + ",Y").PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); word = true; break; case MemoryAccessType.Zpg: addr = ("$" + ceo.Address.ToString("X2")).PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); break; case MemoryAccessType.ZpgX: addr = ("$" + ceo.Address.ToString("X2") + ",X").PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); break; case MemoryAccessType.ZpgY: addr = ("$" + ceo.Address.ToString("X2") + ",Y").PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); break; case MemoryAccessType.Indirect: addr = ("($" + ceo.Address.ToString("X4") + ")").PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); word = true; break; case MemoryAccessType.XIndirect: addr = ("($" + ceo.Address.ToString("X2") + ",X)").PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); break; case MemoryAccessType.IndirectY: addr = ("($" + ceo.Address.ToString("X2") + "),Y").PadRight(10, ' ') + "; #" + ceo.Data.ToString("X2"); break; default: addr = "[UNKNOWN]"; break; } var str = ("$" + ceo.PC.ToString("X4") + " " + ( ((int)ceo.Opcode).ToString("X2") + (ceo.MemoryAccessType != MemoryAccessType.None ? " " + ceo.B1.ToString("X2") : "") + (word ? " " + ceo.B2.ToString("X2") : "") ).PadRight(9, ' ') + _opcodeStr[(int)ceo.Opcode] + " " + addr.PadRight(20, ' ') ) + "A:" + Reg.A.ToString("X2") + (Reg.A != ceo.RegBefore.A ? "->" + ceo.RegBefore.A.ToString("X2") : " ") + " X:" + Reg.X.ToString("X2") + (Reg.X != ceo.RegBefore.X ? "->" + ceo.RegBefore.X.ToString("X2") : " ") + " Y:" + Reg.Y.ToString("X2") + (Reg.Y != ceo.RegBefore.Y ? "->" + ceo.RegBefore.Y.ToString("X2") : " ") + " SP:" + Reg.SP.ToString("X2") + (Reg.SP != ceo.RegBefore.SP ? "->" + ceo.RegBefore.SP.ToString("X2") : " ") + " " + (Reg.Flag.N ? (Reg.Flag.N == ceo.RegBefore.Flag.N ? "N" : "n") : ".") + (Reg.Flag.V ? (Reg.Flag.V == ceo.RegBefore.Flag.V ? "V" : "v") : ".") + " " + (Reg.Flag.B ? (Reg.Flag.B == ceo.RegBefore.Flag.B ? "B" : "b") : ".") + (Reg.Flag.D ? (Reg.Flag.D == ceo.RegBefore.Flag.D ? "D" : "d") : ".") + (Reg.Flag.I ? (Reg.Flag.I == ceo.RegBefore.Flag.I ? "I" : "i") : ".") + (Reg.Flag.Z ? (Reg.Flag.Z == ceo.RegBefore.Flag.Z ? "Z" : "z") : ".") + (Reg.Flag.C ? (Reg.Flag.C == ceo.RegBefore.Flag.C ? "C" : "c") : ".") + " " + ceo.Opcode ; Trace.WriteLine(str); }