diff --git a/Core/Memory/MemoryBus.cs b/Core/Memory/MemoryBus.cs
index 43d613a..b5295fa 100644
--- a/Core/Memory/MemoryBus.cs
+++ b/Core/Memory/MemoryBus.cs
@@ -60,10 +60,6 @@ namespace Core.Memory
// Copy the ROM
Array.Copy(romData, 0, _memory, 0, romData.Length);
}
-
- public void ClearRam()
- {
- //To Do
- }
+
}
}
\ No newline at end of file
diff --git a/Desktop/DebuggerForm.Designer.cs b/Desktop/DebuggerForm.Designer.cs
index 64e9acd..211b446 100644
--- a/Desktop/DebuggerForm.Designer.cs
+++ b/Desktop/DebuggerForm.Designer.cs
@@ -28,6 +28,7 @@
///
private void InitializeComponent()
{
+ components = new System.ComponentModel.Container();
lblAF = new Label();
lblBC = new Label();
lblDE = new Label();
@@ -54,94 +55,95 @@
lblIff2 = new Label();
lblIE = new Label();
btnReset = new Button();
+ uiUpdateTimer = new System.Windows.Forms.Timer(components);
SuspendLayout();
//
// lblAF
//
lblAF.AutoSize = true;
- lblAF.Location = new Point(12, 9);
+ lblAF.Location = new Point(10, 7);
lblAF.Margin = new Padding(2, 0, 2, 0);
lblAF.Name = "lblAF";
- lblAF.Size = new Size(33, 25);
+ lblAF.Size = new Size(26, 20);
lblAF.TabIndex = 0;
lblAF.Text = "AF";
//
// lblBC
//
lblBC.AutoSize = true;
- lblBC.Location = new Point(11, 60);
+ lblBC.Location = new Point(9, 48);
lblBC.Margin = new Padding(2, 0, 2, 0);
lblBC.Name = "lblBC";
- lblBC.Size = new Size(33, 25);
+ lblBC.Size = new Size(27, 20);
lblBC.TabIndex = 1;
lblBC.Text = "BC";
//
// lblDE
//
lblDE.AutoSize = true;
- lblDE.Location = new Point(12, 125);
+ lblDE.Location = new Point(10, 100);
lblDE.Margin = new Padding(2, 0, 2, 0);
lblDE.Name = "lblDE";
- lblDE.Size = new Size(34, 25);
+ lblDE.Size = new Size(28, 20);
lblDE.TabIndex = 2;
lblDE.Text = "DE";
//
// lblHL
//
lblHL.AutoSize = true;
- lblHL.Location = new Point(12, 188);
+ lblHL.Location = new Point(10, 150);
lblHL.Margin = new Padding(2, 0, 2, 0);
lblHL.Name = "lblHL";
- lblHL.Size = new Size(33, 25);
+ lblHL.Size = new Size(27, 20);
lblHL.TabIndex = 3;
lblHL.Text = "HL";
//
// lblPC
//
lblPC.AutoSize = true;
- lblPC.Location = new Point(11, 250);
+ lblPC.Location = new Point(9, 200);
lblPC.Margin = new Padding(2, 0, 2, 0);
lblPC.Name = "lblPC";
- lblPC.Size = new Size(33, 25);
+ lblPC.Size = new Size(26, 20);
lblPC.TabIndex = 4;
lblPC.Text = "PC";
//
// lblSP
//
lblSP.AutoSize = true;
- lblSP.Location = new Point(11, 315);
+ lblSP.Location = new Point(9, 252);
lblSP.Margin = new Padding(2, 0, 2, 0);
lblSP.Name = "lblSP";
- lblSP.Size = new Size(32, 25);
+ lblSP.Size = new Size(25, 20);
lblSP.TabIndex = 6;
lblSP.Text = "SP";
//
// lblFlags
//
lblFlags.AutoSize = true;
- lblFlags.Location = new Point(110, 65);
+ lblFlags.Location = new Point(88, 52);
lblFlags.Margin = new Padding(2, 0, 2, 0);
lblFlags.Name = "lblFlags";
- lblFlags.Size = new Size(53, 25);
+ lblFlags.Size = new Size(43, 20);
lblFlags.TabIndex = 7;
lblFlags.Text = "Flags";
//
// lblTStates
//
lblTStates.AutoSize = true;
- lblTStates.Location = new Point(110, 9);
+ lblTStates.Location = new Point(88, 7);
lblTStates.Margin = new Padding(2, 0, 2, 0);
lblTStates.Name = "lblTStates";
- lblTStates.Size = new Size(75, 25);
+ lblTStates.Size = new Size(63, 20);
lblTStates.TabIndex = 8;
lblTStates.Text = "T-States";
//
// txtMemoryStart
//
- txtMemoryStart.Location = new Point(375, 26);
+ txtMemoryStart.Location = new Point(300, 21);
txtMemoryStart.Margin = new Padding(2);
txtMemoryStart.Name = "txtMemoryStart";
- txtMemoryStart.Size = new Size(150, 31);
+ txtMemoryStart.Size = new Size(121, 27);
txtMemoryStart.TabIndex = 9;
txtMemoryStart.Text = "Memory Start";
txtMemoryStart.TextAlign = HorizontalAlignment.Center;
@@ -149,10 +151,10 @@
//
// btnStep
//
- btnStep.Location = new Point(8, 522);
+ btnStep.Location = new Point(6, 418);
btnStep.Margin = new Padding(2);
btnStep.Name = "btnStep";
- btnStep.Size = new Size(112, 34);
+ btnStep.Size = new Size(90, 27);
btnStep.TabIndex = 12;
btnStep.Text = "Step";
btnStep.UseVisualStyleBackColor = true;
@@ -160,21 +162,20 @@
//
// btnRun
//
- btnRun.Location = new Point(149, 522);
+ btnRun.Location = new Point(119, 418);
btnRun.Margin = new Padding(2);
btnRun.Name = "btnRun";
- btnRun.Size = new Size(112, 34);
+ btnRun.Size = new Size(90, 27);
btnRun.TabIndex = 13;
btnRun.Text = "Run";
btnRun.UseVisualStyleBackColor = true;
- btnRun.Click += btnRun_Click;
//
// btnRefreshMemory
//
- btnRefreshMemory.Location = new Point(531, 26);
+ btnRefreshMemory.Location = new Point(425, 21);
btnRefreshMemory.Margin = new Padding(2);
btnRefreshMemory.Name = "btnRefreshMemory";
- btnRefreshMemory.Size = new Size(112, 34);
+ btnRefreshMemory.Size = new Size(90, 27);
btnRefreshMemory.TabIndex = 14;
btnRefreshMemory.Text = "Refresh Memory";
btnRefreshMemory.UseVisualStyleBackColor = true;
@@ -182,137 +183,134 @@
//
// txtMemoryView
//
- txtMemoryView.Location = new Point(110, 100);
+ txtMemoryView.Location = new Point(88, 80);
txtMemoryView.Margin = new Padding(2);
txtMemoryView.Name = "txtMemoryView";
- txtMemoryView.Size = new Size(519, 243);
+ txtMemoryView.Size = new Size(416, 195);
txtMemoryView.TabIndex = 15;
txtMemoryView.Text = "Memory View Window";
//
// lstDisassembly
//
lstDisassembly.FormattingEnabled = true;
- lstDisassembly.ItemHeight = 25;
- lstDisassembly.Location = new Point(654, 14);
+ lstDisassembly.Location = new Point(523, 11);
lstDisassembly.Margin = new Padding(2);
lstDisassembly.Name = "lstDisassembly";
- lstDisassembly.Size = new Size(314, 329);
+ lstDisassembly.Size = new Size(252, 264);
lstDisassembly.TabIndex = 16;
//
// lstStack
//
lstStack.FormattingEnabled = true;
- lstStack.ItemHeight = 25;
- lstStack.Location = new Point(974, 14);
+ lstStack.Location = new Point(779, 11);
lstStack.Margin = new Padding(2);
lstStack.Name = "lstStack";
- lstStack.Size = new Size(162, 329);
+ lstStack.Size = new Size(130, 264);
lstStack.TabIndex = 17;
//
// btnExit
//
- btnExit.Location = new Point(1019, 520);
+ btnExit.Location = new Point(815, 416);
btnExit.Margin = new Padding(2);
btnExit.Name = "btnExit";
- btnExit.Size = new Size(112, 34);
+ btnExit.Size = new Size(90, 27);
btnExit.TabIndex = 18;
btnExit.Text = "Full Exit";
btnExit.UseVisualStyleBackColor = true;
- btnExit.Click += btnExit_Click;
//
// label1
//
label1.AutoSize = true;
- label1.Location = new Point(250, 348);
- label1.Margin = new Padding(4, 0, 4, 0);
+ label1.Location = new Point(289, 284);
label1.Name = "label1";
- label1.Size = new Size(97, 25);
+ label1.Size = new Size(81, 20);
label1.TabIndex = 19;
label1.Text = "Breakpoint";
//
// txtBreakpoint
//
- txtBreakpoint.Location = new Point(470, 351);
- txtBreakpoint.Margin = new Padding(4);
+ txtBreakpoint.Location = new Point(376, 281);
txtBreakpoint.Name = "txtBreakpoint";
- txtBreakpoint.Size = new Size(155, 31);
+ txtBreakpoint.Size = new Size(125, 27);
txtBreakpoint.TabIndex = 20;
//
// label2
//
label2.AutoSize = true;
- label2.Location = new Point(291, 26);
- label2.Margin = new Padding(4, 0, 4, 0);
+ label2.Location = new Point(233, 21);
label2.Name = "label2";
- label2.Size = new Size(77, 25);
+ label2.Size = new Size(62, 20);
label2.TabIndex = 21;
label2.Text = "Address";
//
// lblIX
//
lblIX.AutoSize = true;
- lblIX.Location = new Point(11, 372);
+ lblIX.Location = new Point(9, 298);
lblIX.Margin = new Padding(2, 0, 2, 0);
lblIX.Name = "lblIX";
- lblIX.Size = new Size(28, 25);
+ lblIX.Size = new Size(22, 20);
lblIX.TabIndex = 22;
lblIX.Text = "IX";
//
// lblIY
//
lblIY.AutoSize = true;
- lblIY.Location = new Point(12, 430);
+ lblIY.Location = new Point(10, 344);
lblIY.Margin = new Padding(2, 0, 2, 0);
lblIY.Name = "lblIY";
- lblIY.Size = new Size(27, 25);
+ lblIY.Size = new Size(21, 20);
lblIY.TabIndex = 23;
lblIY.Text = "IY";
//
// lblIff1
//
lblIff1.AutoSize = true;
- lblIff1.Location = new Point(110, 372);
- lblIff1.Margin = new Padding(4, 0, 4, 0);
+ lblIff1.Location = new Point(88, 298);
lblIff1.Name = "lblIff1";
- lblIff1.Size = new Size(45, 25);
+ lblIff1.Size = new Size(35, 20);
lblIff1.TabIndex = 24;
lblIff1.Text = "IFF1";
//
// lblIff2
//
lblIff2.AutoSize = true;
- lblIff2.Location = new Point(110, 431);
- lblIff2.Margin = new Padding(4, 0, 4, 0);
+ lblIff2.Location = new Point(88, 345);
lblIff2.Name = "lblIff2";
- lblIff2.Size = new Size(45, 25);
+ lblIff2.Size = new Size(35, 20);
lblIff2.TabIndex = 25;
lblIff2.Text = "IFF2";
//
// lblIE
//
lblIE.AutoSize = true;
- lblIE.Location = new Point(250, 431);
- lblIE.Margin = new Padding(4, 0, 4, 0);
+ lblIE.Location = new Point(200, 345);
lblIE.Name = "lblIE";
- lblIE.Size = new Size(133, 25);
+ lblIE.Size = new Size(109, 20);
lblIE.TabIndex = 26;
lblIE.Text = "Interrupt Mode";
//
// btnReset
//
- btnReset.Location = new Point(883, 520);
+ btnReset.Location = new Point(372, 313);
+ btnReset.Margin = new Padding(2);
btnReset.Name = "btnReset";
- btnReset.Size = new Size(112, 34);
+ btnReset.Size = new Size(132, 27);
btnReset.TabIndex = 27;
- btnReset.Text = "Hard Reset";
+ btnReset.Text = "Set Breakpoint";
btnReset.UseVisualStyleBackColor = true;
- btnReset.Click += btnReset_Click;
+ btnReset.Click += btnSetBreakpoint_Click;
+ //
+ // uiUpdateTimer
+ //
+ uiUpdateTimer.Enabled = true;
+ uiUpdateTimer.Tick += uiUpdateTimer_Tick;
//
// DebuggerForm
//
- AutoScaleDimensions = new SizeF(10F, 25F);
+ AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
- ClientSize = new Size(1160, 568);
+ ClientSize = new Size(928, 454);
Controls.Add(btnReset);
Controls.Add(lblIE);
Controls.Add(lblIff2);
@@ -373,6 +371,7 @@
private Label lblIff2;
private Label lblIE;
private Button btnReset;
+ private System.Windows.Forms.Timer uiUpdateTimer;
//private TextBox textBox4;
}
}
\ No newline at end of file
diff --git a/Desktop/DebuggerForm.cs b/Desktop/DebuggerForm.cs
index 0a2fce5..40a8f0e 100644
--- a/Desktop/DebuggerForm.cs
+++ b/Desktop/DebuggerForm.cs
@@ -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()
{
diff --git a/Desktop/DebuggerForm.resx b/Desktop/DebuggerForm.resx
index 5261a14..7d0a62d 100644
--- a/Desktop/DebuggerForm.resx
+++ b/Desktop/DebuggerForm.resx
@@ -120,4 +120,7 @@
17, 17
+
+ 182, 17
+
\ No newline at end of file
diff --git a/Desktop/Form1.Designer.cs b/Desktop/Form1.Designer.cs
index 39f7353..076b9ad 100644
--- a/Desktop/Form1.Designer.cs
+++ b/Desktop/Form1.Designer.cs
@@ -32,7 +32,16 @@
menuStrip1 = new MenuStrip();
fileToolStripMenuItem = new ToolStripMenuItem();
openToolStripMenuItem = new ToolStripMenuItem();
- openSnapshotToolStripMenuItem = new ToolStripMenuItem();
+ tAPToolStripMenuItem = new ToolStripMenuItem();
+ sNAToolStripMenuItem = new ToolStripMenuItem();
+ exitToolStripMenuItem = new ToolStripMenuItem();
+ viewToolStripMenuItem = new ToolStripMenuItem();
+ debuggerToolStripMenuItem = new ToolStripMenuItem();
+ machineToolStripMenuItem = new ToolStripMenuItem();
+ runToolStripMenuItem = new ToolStripMenuItem();
+ resetToolStripMenuItem = new ToolStripMenuItem();
+ stepToolStripMenuItem = new ToolStripMenuItem();
+ resetToolStripMenuItem1 = new ToolStripMenuItem();
((System.ComponentModel.ISupportInitialize)picScreen).BeginInit();
menuStrip1.SuspendLayout();
SuspendLayout();
@@ -40,10 +49,9 @@
// picScreen
//
picScreen.BackColor = Color.Black;
- picScreen.Location = new Point(13, 33);
- picScreen.Margin = new Padding(4);
+ picScreen.Location = new Point(10, 26);
picScreen.Name = "picScreen";
- picScreen.Size = new Size(900, 720);
+ picScreen.Size = new Size(720, 576);
picScreen.SizeMode = PictureBoxSizeMode.Zoom;
picScreen.TabIndex = 0;
picScreen.TabStop = false;
@@ -51,44 +59,107 @@
// menuStrip1
//
menuStrip1.ImageScalingSize = new Size(24, 24);
- menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem });
+ menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, viewToolStripMenuItem, machineToolStripMenuItem });
menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1";
- menuStrip1.Size = new Size(922, 33);
+ menuStrip1.Padding = new Padding(5, 2, 0, 2);
+ menuStrip1.Size = new Size(738, 28);
menuStrip1.TabIndex = 1;
menuStrip1.Text = "menuStrip1";
//
// fileToolStripMenuItem
//
- fileToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { openToolStripMenuItem, openSnapshotToolStripMenuItem });
+ fileToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { openToolStripMenuItem, exitToolStripMenuItem });
fileToolStripMenuItem.Name = "fileToolStripMenuItem";
- fileToolStripMenuItem.Size = new Size(54, 29);
+ fileToolStripMenuItem.Size = new Size(46, 24);
fileToolStripMenuItem.Text = "File";
//
// openToolStripMenuItem
//
+ openToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { tAPToolStripMenuItem, sNAToolStripMenuItem });
openToolStripMenuItem.Name = "openToolStripMenuItem";
- openToolStripMenuItem.Size = new Size(270, 34);
- openToolStripMenuItem.Text = "Open TAP";
- openToolStripMenuItem.Click += loadTAPToolStripMenuItem_Click;
+ openToolStripMenuItem.Size = new Size(128, 26);
+ openToolStripMenuItem.Text = "Open";
//
- // openSnapshotToolStripMenuItem
+ // tAPToolStripMenuItem
//
- openSnapshotToolStripMenuItem.Name = "openSnapshotToolStripMenuItem";
- openSnapshotToolStripMenuItem.Size = new Size(270, 34);
- openSnapshotToolStripMenuItem.Text = "Open Snapshot";
- openSnapshotToolStripMenuItem.Click += openSNAToolStripMenuItem_Click;
+ tAPToolStripMenuItem.Name = "tAPToolStripMenuItem";
+ tAPToolStripMenuItem.Size = new Size(121, 26);
+ tAPToolStripMenuItem.Text = "TAP";
+ tAPToolStripMenuItem.Click += loadTAPToolStripMenuItem_Click;
+ //
+ // sNAToolStripMenuItem
+ //
+ sNAToolStripMenuItem.Name = "sNAToolStripMenuItem";
+ sNAToolStripMenuItem.Size = new Size(121, 26);
+ sNAToolStripMenuItem.Text = "SNA";
+ sNAToolStripMenuItem.Click += openSNAToolStripMenuItem_Click;
+ //
+ // exitToolStripMenuItem
+ //
+ exitToolStripMenuItem.Name = "exitToolStripMenuItem";
+ exitToolStripMenuItem.Size = new Size(128, 26);
+ exitToolStripMenuItem.Text = "Exit";
+ exitToolStripMenuItem.Click += btnExit_Click;
+ //
+ // viewToolStripMenuItem
+ //
+ viewToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { debuggerToolStripMenuItem });
+ viewToolStripMenuItem.Name = "viewToolStripMenuItem";
+ viewToolStripMenuItem.Size = new Size(55, 24);
+ viewToolStripMenuItem.Text = "View";
+ //
+ // debuggerToolStripMenuItem
+ //
+ debuggerToolStripMenuItem.Name = "debuggerToolStripMenuItem";
+ debuggerToolStripMenuItem.Size = new Size(224, 26);
+ debuggerToolStripMenuItem.Text = "Debugger";
+ debuggerToolStripMenuItem.Click += openDebuggerToolStripMenuItem_Click;
+ //
+ // machineToolStripMenuItem
+ //
+ machineToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { runToolStripMenuItem, resetToolStripMenuItem, stepToolStripMenuItem, resetToolStripMenuItem1 });
+ machineToolStripMenuItem.Name = "machineToolStripMenuItem";
+ machineToolStripMenuItem.Size = new Size(79, 24);
+ machineToolStripMenuItem.Text = "Machine";
+ //
+ // runToolStripMenuItem
+ //
+ runToolStripMenuItem.Name = "runToolStripMenuItem";
+ runToolStripMenuItem.Size = new Size(129, 26);
+ runToolStripMenuItem.Text = "Run";
+ runToolStripMenuItem.Click += btnRun_Click;
+ //
+ // resetToolStripMenuItem
+ //
+ resetToolStripMenuItem.Name = "resetToolStripMenuItem";
+ resetToolStripMenuItem.Size = new Size(129, 26);
+ resetToolStripMenuItem.Text = "Pause";
+ resetToolStripMenuItem.Click += btnPause_Click;
+ //
+ // stepToolStripMenuItem
+ //
+ stepToolStripMenuItem.Name = "stepToolStripMenuItem";
+ stepToolStripMenuItem.Size = new Size(129, 26);
+ stepToolStripMenuItem.Text = "Step";
+ stepToolStripMenuItem.Click += btnStep_Click;
+ //
+ // resetToolStripMenuItem1
+ //
+ resetToolStripMenuItem1.Name = "resetToolStripMenuItem1";
+ resetToolStripMenuItem1.Size = new Size(129, 26);
+ resetToolStripMenuItem1.Text = "Reset";
+ resetToolStripMenuItem1.Click += btnReset_Click;
//
// Form1
//
- AutoScaleDimensions = new SizeF(10F, 25F);
+ AutoScaleDimensions = new SizeF(8F, 20F);
AutoScaleMode = AutoScaleMode.Font;
- ClientSize = new Size(922, 760);
+ ClientSize = new Size(738, 608);
Controls.Add(picScreen);
Controls.Add(menuStrip1);
KeyPreview = true;
MainMenuStrip = menuStrip1;
- Margin = new Padding(4);
Name = "Form1";
Text = "Parsons Sinclair ZX Spectrum 48K - 2026";
((System.ComponentModel.ISupportInitialize)picScreen).EndInit();
@@ -104,6 +175,15 @@
private MenuStrip menuStrip1;
private ToolStripMenuItem fileToolStripMenuItem;
private ToolStripMenuItem openToolStripMenuItem;
- private ToolStripMenuItem openSnapshotToolStripMenuItem;
+ private ToolStripMenuItem tAPToolStripMenuItem;
+ private ToolStripMenuItem sNAToolStripMenuItem;
+ private ToolStripMenuItem exitToolStripMenuItem;
+ private ToolStripMenuItem viewToolStripMenuItem;
+ private ToolStripMenuItem debuggerToolStripMenuItem;
+ private ToolStripMenuItem machineToolStripMenuItem;
+ private ToolStripMenuItem runToolStripMenuItem;
+ private ToolStripMenuItem resetToolStripMenuItem;
+ private ToolStripMenuItem stepToolStripMenuItem;
+ private ToolStripMenuItem resetToolStripMenuItem1;
}
}
diff --git a/Desktop/Form1.cs b/Desktop/Form1.cs
index 7a14a07..82eb89a 100644
--- a/Desktop/Form1.cs
+++ b/Desktop/Form1.cs
@@ -16,6 +16,11 @@ namespace Desktop
private IO_Bus _simpleIoBus = null!;
private TapManager _tapManager = null!;
private int _ulaFrameCount = 0;
+ private bool _isRunning = false;
+ private bool _isPaused = false;
+ private bool _resetFlag = false;
+ public ushort? Breakpoint = null; // Public so the debugger can set it!
+ private DebuggerForm _debugger = null;
// The 16 physical colors of the ZX Spectrum (ARGB format)
private readonly int[] SpectrumColors = new int[]
@@ -61,16 +66,88 @@ namespace Desktop
_cpu = new Z80(_memoryBus, _simpleIoBus, _tapManager);
// Pass 'this' so the DebuggerForm can talk back to this main window
- DebuggerForm debugger = new DebuggerForm(_cpu, _memoryBus, this);
- debugger.Show();
+ //DebuggerForm debugger = new DebuggerForm(_cpu, _memoryBus, this);
+ //debugger.Show();
}
catch (Exception ex)
{
MessageBox.Show($"Failed to initialize emulator:\n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
+ StartEmulationLoop();
+ }
+
+ private void StartEmulationLoop()
+ {
+ if (_isRunning) return;
+ _isRunning = true;
+ _isPaused = false;
+
+ Task.Run(() =>
+ {
+ try
+ {
+ const int TStatesPerFrame = 69888;
+ long nextFrameTargetTStates = _cpu.TotalTStates + TStatesPerFrame;
+ var stopwatch = System.Diagnostics.Stopwatch.StartNew();
+ long frameCount = 0;
+
+ while (_isRunning)
+ {
+ //if(_resetFlag)
+ //{
+ // _resetFlag = false;
+ // stopwatch.Reset();
+ // nextFrameTargetTStates = _cpu.TotalTStates + TStatesPerFrame;
+ // frameCount = 0;
+ //}
+ if (_isPaused)
+ {
+ System.Threading.Thread.Sleep(10); // Don't melt the host CPU while paused
+ continue;
+ }
+
+ // --- Breakpoint Check ---
+ if (Breakpoint.HasValue && _cpu.PC == Breakpoint.Value)
+ {
+ _isPaused = true;
+ // Optional: You could force the debugger to open here!
+ continue;
+ }
+
+ // --- Execute Instruction ---
+ _cpu.Step();
+
+ // --- Check for End of Frame ---
+ if (_cpu.TotalTStates >= nextFrameTargetTStates)
+ {
+ _cpu.RequestInterrupt();
+ nextFrameTargetTStates += TStatesPerFrame;
+ frameCount++;
+
+ // Render the screen
+ this.Invoke((MethodInvoker)delegate { RenderScreen(); });
+
+ // Throttle to real-time (50 FPS = 20ms)
+ long targetTimeMs = frameCount * 20;
+ long elapsedMs = stopwatch.ElapsedMilliseconds;
+
+ if (elapsedMs < targetTimeMs)
+ {
+ System.Threading.Thread.Sleep((int)(targetTimeMs - elapsedMs));
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ _isPaused = true;
+ this.Invoke((MethodInvoker)delegate {
+ MessageBox.Show(ex.Message, "CPU Crash", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ });
+ }
+ });
}
- // Inside Desktop/Form1.cs
private void loadTAPToolStripMenuItem_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog())
@@ -101,6 +178,42 @@ namespace Desktop
}
}
+ private void btnRun_Click(object sender, EventArgs e) => _isPaused = false;
+
+ private void btnPause_Click(object sender, EventArgs e) => _isPaused = true;
+
+ private void btnStep_Click(object sender, EventArgs e)
+ {
+ if (_isPaused) _cpu.Step();
+ }
+
+ private void btnReset_Click(object sender, EventArgs e)
+ {
+ //_resetFlag = true;
+ _isPaused = true;
+ _cpu.Reset();
+ _memoryBus.CleanRAMData();
+ _isPaused = false;
+ }
+
+ private void btnExit_Click(object sender, EventArgs e)
+ {
+ Environment.Exit(0);
+ }
+
+ private void openDebuggerToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+ if (_debugger == null || _debugger.IsDisposed)
+ {
+ _debugger = new DebuggerForm(_cpu, _memoryBus, this);
+ _debugger.Show();
+ }
+ else
+ {
+ _debugger.BringToFront();
+ }
+ }
+
// Public so the Debugger's background thread can call it 50 times a second
public void RenderScreen()
{