Changed the structure of the emulator

This commit is contained in:
2026-04-20 14:31:06 +01:00
parent 7464b29fca
commit adbf64a84d
6 changed files with 296 additions and 240 deletions

View File

@@ -40,9 +40,17 @@ namespace Desktop
{
MessageBox.Show(ex.Message, "CPU Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
}
private void btnSetBreakpoint_Click(object sender, EventArgs e) // Hook this to a button or text changed event
{
if (ushort.TryParse(txtBreakpoint.Text, System.Globalization.NumberStyles.HexNumber, null, out ushort parsedBp))
{
UpdateDisplay();
_mainForm.Breakpoint = parsedBp;
}
else
{
_mainForm.Breakpoint = null;
}
}
@@ -51,156 +59,13 @@ namespace Desktop
UpdateDisplay();
}
private async void btnRun_Click(object sender, EventArgs e)
private void uiUpdateTimer_Tick(object sender, EventArgs e)
{
//Stops
if (_isRunning)
{
_isRunning = false;
btnRun.Text = "Run";
return;
}
//Parse the Breakpoint
if (!string.IsNullOrWhiteSpace(txtBreakpoint.Text))
{
if (ushort.TryParse(txtBreakpoint.Text, System.Globalization.NumberStyles.HexNumber, null, out ushort parsedBp))
{
_breakpoint = parsedBp;
}
else
{
MessageBox.Show("Invalid hex address in breakpoint!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
}
else
{
_breakpoint = null;
}
// Start the run state
_isRunning = true;
btnRun.Text = "Stop";
//Background thread
await Task.Run(() =>
{
try
{
// 1. Setup Frame Timing Variables
const int TStatesPerFrame = 69888;
long nextFrameTargetTStates = _cpu.TotalTStates + TStatesPerFrame;
// 2. Setup Real-World Throttling
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
long frameCount = 0;
while (_isRunning)
{
// --- Breakpoint Check ---
if (_breakpoint.HasValue && _cpu.PC == _breakpoint.Value)
{
_isRunning = false;
break;
}
// --- Execute Instruction ---
_cpu.Step();
//if (_cpu.TotalTStates % 1000 == 0)
//{
// this.Invoke((MethodInvoker)delegate
// {
// UpdateDisplay();
// });
//}
// --- Check for End of Frame ---
if (_cpu.TotalTStates >= nextFrameTargetTStates)
{
// 1. Fire the 50Hz Interrupt!
_cpu.RequestInterrupt();
// 2. Advance the target to the next frame
nextFrameTargetTStates += TStatesPerFrame;
frameCount++;
//3 Render the screen
_mainForm.Invoke((MethodInvoker)delegate
{
_mainForm.RenderScreen();
});
// 4. Throttle to real-time (50 frames per second = 20ms per frame)
long targetTimeMs = frameCount * 20;
long elapsedMs = stopwatch.ElapsedMilliseconds;
if (elapsedMs < targetTimeMs)
{
// The CPU ran too fast! Put the thread to sleep to let reality catch up.
System.Threading.Thread.Sleep((int)(targetTimeMs - elapsedMs));
}
// Optional: Update the UI every 10 frames so you can watch it run safely
// without overwhelming the WinForms rendering engine.
if (frameCount % 1 == 0)
{
this.Invoke((MethodInvoker)delegate
{
UpdateDisplay();
});
}
}
//this.Invoke((MethodInvoker)delegate {
// UpdateDisplay();
// });
}
}
catch (Exception ex)
{
_isRunning = false;
this.Invoke((MethodInvoker)delegate
{
MessageBox.Show(ex.Message, "CPU Break", MessageBoxButtons.OK, MessageBoxIcon.Information);
});
}
});
//update the UI when the background thread finishes
btnRun.Text = "Run";
// Every 100ms, take a snapshot of the CPU state and draw it to the screen.
// This makes the registers look like they are spinning matrix-style while running!
UpdateDisplay();
}
private void btnReset_Click(object sender, EventArgs e)
{
// 1. Safely stop the emulator if it is currently in a Run loop
if (_isRunning)
{
_isRunning = false;
btnRun.Text = "Run";
}
// 2. Power cycle the CPU
_cpu.Reset();
// Note: A true hard reset also wipes the RAM.
// If you add a RAM clear method to your MemoryBus later, call it here!
_memoryBus.ClearRam(); //To Do
// 3. Clear the UI tracking lists
lstDisassembly.Items.Clear();
lstStack.Items.Clear();
// 4. Force a full UI refresh to show the clean slate
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()
{