Added Debugger
This commit is contained in:
176
Desktop/DebuggerForm.cs
Normal file
176
Desktop/DebuggerForm.cs
Normal file
@@ -0,0 +1,176 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using Core.Cpu;
|
||||
using Core.Memory;
|
||||
|
||||
namespace Desktop
|
||||
{
|
||||
public partial class DebuggerForm : Form
|
||||
{
|
||||
private readonly Z80 _cpu;
|
||||
private readonly MemoryBus _memoryBus;
|
||||
|
||||
public DebuggerForm(Z80 cpu, MemoryBus memoryBus)
|
||||
{
|
||||
InitializeComponent();
|
||||
_cpu = cpu;
|
||||
_memoryBus = memoryBus;
|
||||
|
||||
// Set default memory view address
|
||||
txtMemoryStart.Text = "0000";
|
||||
UpdateDisplay();
|
||||
UpdateStackView();
|
||||
UpdateDisassemblyView();
|
||||
}
|
||||
|
||||
private void btnStep_Click(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_cpu.Step();
|
||||
UpdateDisplay();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show(ex.Message, "CPU Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
UpdateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
private void btnRefreshMemory_Click(object sender, EventArgs e)
|
||||
{
|
||||
UpdateDisplay();
|
||||
}
|
||||
|
||||
private void btnExit_Click(object sender, EventArgs e)
|
||||
{
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
// This is the master function that pulls state from the CPU
|
||||
private void UpdateDisplay()
|
||||
{
|
||||
// 1. Update Registers (Formatting as 4-character Hex strings)
|
||||
lblAF.Text = $"AF: {_cpu.AF.Word:X4}";
|
||||
lblBC.Text = $"BC: {_cpu.BC.Word:X4}";
|
||||
lblDE.Text = $"DE: {_cpu.DE.Word:X4}";
|
||||
lblHL.Text = $"HL: {_cpu.HL.Word:X4}";
|
||||
lblPC.Text = $"PC: {_cpu.PC:X4}";
|
||||
lblSP.Text = $"SP: {_cpu.SP:X4}";
|
||||
|
||||
// 2. Update Flags & T-States
|
||||
lblFlags.Text = $"Flags: {_cpu.GetFlagsString()}";
|
||||
lblTStates.Text = $"T-States: {_cpu.TotalTStates}";
|
||||
|
||||
// 3. Update Memory Viewer
|
||||
UpdateMemoryView();
|
||||
}
|
||||
|
||||
private void UpdateMemoryView()
|
||||
{
|
||||
// Try to parse the hex string the user typed in
|
||||
if (!ushort.TryParse(txtMemoryStart.Text, System.Globalization.NumberStyles.HexNumber, null, out ushort startAddress))
|
||||
{
|
||||
txtMemoryView.Text = "Invalid Hex Address!";
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// Read 100 bytes (or roughly 6 lines of 16 bytes)
|
||||
for (int line = 0; line < 7; line++)
|
||||
{
|
||||
ushort currentAddr = (ushort)(startAddress + (line * 16));
|
||||
|
||||
// Print the address header for this line (e.g., "0000: ")
|
||||
sb.Append($"{currentAddr:X4}: ");
|
||||
|
||||
// Print 16 bytes across
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
// Careful not to overflow the 64k address space!
|
||||
if (currentAddr + i <= 0xFFFF)
|
||||
{
|
||||
byte b = _memoryBus.Read((ushort)(currentAddr + i));
|
||||
sb.Append($"{b:X2} ");
|
||||
}
|
||||
}
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
txtMemoryView.Text = sb.ToString();
|
||||
}
|
||||
|
||||
private void UpdateStackView()
|
||||
{
|
||||
lstStack.Items.Clear();
|
||||
|
||||
// The Z80 stack starts at 0xFFFF and grows downwards.
|
||||
// If SP is at the very top (e.g., 0xFFFF), we don't want to read past the end of memory and crash!
|
||||
int itemsToShow = 5;
|
||||
ushort currentSp = _cpu.SP;
|
||||
|
||||
for (int i = 0; i < itemsToShow; i++)
|
||||
{
|
||||
// Prevent reading past 0xFFFF
|
||||
if (currentSp >= 0xFFFE)
|
||||
{
|
||||
lstStack.Items.Add($"{currentSp:X4}: [End of Mem]");
|
||||
break;
|
||||
}
|
||||
|
||||
// Read the 16-bit value (Little-Endian: Low byte first, then High byte)
|
||||
byte low = _memoryBus.Read(currentSp);
|
||||
byte high = _memoryBus.Read((ushort)(currentSp + 1));
|
||||
ushort value = (ushort)((high << 8) | low);
|
||||
|
||||
lstStack.Items.Add($"{currentSp:X4}: {value:X4}");
|
||||
|
||||
// Move to the next 16-bit word on the stack
|
||||
currentSp += 2;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDisassemblyView()
|
||||
{
|
||||
lstDisassembly.Items.Clear();
|
||||
|
||||
ushort currentPc = _cpu.PC;
|
||||
int instructionsToShow = 8;
|
||||
|
||||
for (int i = 0; i < instructionsToShow; i++)
|
||||
{
|
||||
byte opcode = _memoryBus.Read(currentPc);
|
||||
string mnemonic;
|
||||
int instructionLength = 1; // Default to 1 byte long
|
||||
|
||||
// This switch statement will grow as you add more opcodes to the CPU!
|
||||
switch (opcode)
|
||||
{
|
||||
case 0x00:
|
||||
mnemonic = "NOP";
|
||||
break;
|
||||
case 0x3E:
|
||||
// LD A, n (Loads the next byte into register A)
|
||||
byte nextByte = _memoryBus.Read((ushort)(currentPc + 1));
|
||||
mnemonic = $"LD A, 0x{nextByte:X2}";
|
||||
instructionLength = 2; // This instruction takes up 2 bytes
|
||||
break;
|
||||
default:
|
||||
mnemonic = $"UNKNOWN (0x{opcode:X2})";
|
||||
break;
|
||||
}
|
||||
|
||||
// Add to the list box
|
||||
lstDisassembly.Items.Add($"{currentPc:X4}: {mnemonic}");
|
||||
|
||||
// Advance to the start of the next instruction
|
||||
currentPc += (ushort)instructionLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user