Changed the structure of the emulator
This commit is contained in:
@@ -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()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user