/// <summary> /// Resets the CPU, then starts the execution process /// </summary> public void Reset(BreakpointMgr bpm) { // This will cause a hard reset // to run programme at $fffc/$fffd PC = 0xFFFC; // Reset stack SP = 0xFF; // Force 6502 to use 0x4C as first opcode on swith on. This is a // JMP $FFFC - a direct JMP. Opcode = 0x4C; PC--; debugHeader = 0; // Loop provided memory not toally shafted. In real life this doesn't happen, // the CPU blindly reads the byte and hopes it can do something with it. while (Opcode != 0) { Cycle c = new Cycle(PC); // Print the header, allows us to see the opcode and PC // when things go very wrong. DebugHeader(Opcode); // In reality, we could strip out the C below as that is used just for // visual purposes.... ExecuteInstruction(c, Opcode); // Output all registers and flags DebugTail(c, bpm); Opcode = RAM.GetByte(c, PC); } }
/// <summary> /// Output various information to the console. Visual only. /// </summary> /// <param name="c"></param> private void DebugTail(Cycle c, BreakpointMgr bpm) { Console.ForegroundColor = ConsoleColor.Green; Console.Write(c.DebugRow().PadRight(30)); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write(String.Format(" {0:x2} {1:x2} {2:x2} {3:x2} ", A, X, Y, SP)); Console.ForegroundColor = ConsoleColor.DarkCyan; Console.Write(ToBinary(Flags)); Console.ForegroundColor = ConsoleColor.Blue; Console.Write(" " + c.Operand.Cycles + "+" + c.Operand.ExtraCycles + ":"); if (c.ActualCycles < c.Operand.Cycles || c.ActualCycles > c.Operand.Cycles + c.Operand.ExtraCycles) { Console.ForegroundColor = ConsoleColor.Yellow; } Console.WriteLine(c.ActualCycles); BreakPointSet bps = bpm.ShallIBreak(this, c); if (bps != null || bpm.StepMode) { if (bps != null) { Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(bps); } var key = Console.ReadKey(); if (key.Key == ConsoleKey.Enter) { bpm.StepMode = false; } else { bpm.StepMode = true; } } }
static void Main(string[] args) { Console.WriteLine("6502 Emulator\n"); CPU cpu = new CPU(); // Emulate the 6502 start up, which looks for a vector at $FFFC/$FFFD // and starts execution from there. Need to start one code before as // we musn't have zero at the load point - any value other than 0 good. // This is not required if we don't mind blue screen of death situations cpu.RAM.LoadMemnory(0xFFFB, new byte[] { 0xff, 0x00, 0x50 }); // Variables for testing - including JMP($) for subroutine cpu.RAM.LoadMemnory(0x0302, new byte[] { 0xaa, 0xbb, 23, 0x50 }); // JSR and RET Subroutine Test cpu.RAM.LoadMemnory(0x6040, new byte[] { 0xa2, 0x05, 0x8a, 0xaa, 0xc8, 0x98, 0xc8, 0xa8, 0x88, 0xe8, 0xca, 0x60 }); // Main code. Tests nearly all functions, then finally JMPs to Fibonacci code cpu.RAM.LoadMemnory(0x5000, new byte[] { 0x6c, 0x04, 0x03, 0xa1, 0xed, 0xa1, 0x00, 0xa1, 0xed, 0xa9, 0x01, 0xbd, 0x02, 0x01, 0xb1, 0xff, 0xa2, 127, 0xe8, 0xa2, 0xff, 0xe8, 0xca, 0xd0, 0x01, 0xea, 0xa2, 0x04, 0xca, 0xd0, 0xfd, 0xca, 0x20, 0x40, 0x60, 0xEA, 0x38, 0x18, 0xf8, 0xd8, 0x78, 0x58, 0x8d, 0x00, 0x40, 0xa9, 0x0, 0xad, 0x00, 0x40, 0x8e, 0x00, 0x40, 0xad, 0x00, 0x40, 0x4c, 0x00, 0x70 }); // Fibonacci Sequence cpu.RAM.LoadMemnory(0x7000, new byte[] { 0xa0, 0x07, 0xa9, 0x00, 0x8d, 0x00, 0x40, 0xa9, 0x01, 0xaa, 0x18, 0x6d, 0x00, 0x40, 0x8e, 0x00, 0x40, 0x88, 0xd0, 0xf5, 0xea }); // Add some breakpoints for fun. BreakpointMgr mgr = new BreakpointMgr(); BreakPointSet bps = new BreakPointSet(5, "5th time at 0x700e"); mgr.AddBreakPointSet(bps); bps.AddBreakPoint("PC", 0x700e); BreakPointSet bps2 = new BreakPointSet(1, "A = 8 and Y=2 for the first time"); mgr.AddBreakPointSet(bps2); bps2.AddBreakPoint("A", 0x08); bps2.AddBreakPoint("Y", 0x02); // You dont need to name the break point, and if you dont provide a count // it will assume the first time the breakpoint is hit. BreakPointSet bps3 = new BreakPointSet(); mgr.AddBreakPointSet(bps3); bps3.AddBreakPoint("Opcode", 0x18); BreakPointSet bps4 = new BreakPointSet(1, "Stack has exactly one entry on"); mgr.AddBreakPointSet(bps4); bps4.AddBreakPoint("SP", 0xfd); BreakPointSet bps5 = new BreakPointSet(1, "Carry flag set"); mgr.AddBreakPointSet(bps5); bps5.AddBreakPoint("C", 0x1); // Simulate a reset and start the execution cpu.Reset(mgr); }