diff --git a/Core/Io/TapManager.cs b/Core/Io/TapManager.cs index bdc4722..64d7c94 100644 --- a/Core/Io/TapManager.cs +++ b/Core/Io/TapManager.cs @@ -145,10 +145,24 @@ namespace Core.Io CalculateNextDataPulse(); } break; - + //case TapeState.Pause: + // // The .TAP Format Auto-Stop Heuristic: + // if (_currentBlock != null && _currentBlock.Length > 0 && _currentBlock[0] == 0x00) + // { + // // 1. It was a Header block. The ROM is waiting for the Data right now! Keep spinning. + // LoadNextBlock(); + // } + // else + // { + // // 2. It was a Data block (or custom). The "file" is done. + // // Auto-Stop the tape deck so we don't accidentally play the next level into the void. + // _state = TapeState.Idle; + // _currentBlock = null; + // } + // break; case TapeState.Pause: _state = TapeState.Idle; - //LoadNextBlock(); + LoadNextBlock(); break; } } @@ -170,12 +184,14 @@ namespace Core.Io //public bool HasBlocks => _blocks.Count > 0; // Change this line: - public bool HasBlocks => _blocks.Count > 0 || _currentBlock != null; + //public bool HasBlocks => _blocks.Count > 0 || _currentBlock != null; + // Only consider _currentBlock valid if we are actively playing it! + public bool HasBlocks => _blocks.Count > 0 || (_currentBlock != null && _state != TapeState.Idle && _state != TapeState.Pause); public byte[] GetNextBlock() { - // If a block is loaded into the tape deck, yank it immediately - if (_currentBlock != null) + // Yank the current block ONLY if it is actively playing + if (_currentBlock != null && _state != TapeState.Idle && _state != TapeState.Pause) { byte[] blockToReturn = _currentBlock; _state = TapeState.Idle; // Ensure the tape deck is stopped @@ -183,7 +199,9 @@ namespace Core.Io return blockToReturn; } - // Otherwise, pull directly from the queue + // Otherwise, pull directly from the unplayed queue + _state = TapeState.Idle; // Stop the tape deck just in case + _currentBlock = null; return _blocks.Count > 0 ? _blocks.Dequeue() : null; } } diff --git a/Desktop/DebuggerForm.Designer.cs b/Desktop/DebuggerForm.Designer.cs index cbcb374..65eb090 100644 --- a/Desktop/DebuggerForm.Designer.cs +++ b/Desktop/DebuggerForm.Designer.cs @@ -55,6 +55,7 @@ lblFrames = new Label(); lblFPS = new Label(); lblFrameTime = new Label(); + richTextBox1 = new RichTextBox(); SuspendLayout(); // // lblAF @@ -164,14 +165,14 @@ txtMemoryView.Location = new Point(88, 80); txtMemoryView.Margin = new Padding(2); txtMemoryView.Name = "txtMemoryView"; - txtMemoryView.Size = new Size(416, 195); + txtMemoryView.Size = new Size(443, 895); txtMemoryView.TabIndex = 15; txtMemoryView.Text = "Memory View Window"; // // lstDisassembly // lstDisassembly.FormattingEnabled = true; - lstDisassembly.Location = new Point(523, 11); + lstDisassembly.Location = new Point(567, 8); lstDisassembly.Margin = new Padding(2); lstDisassembly.Name = "lstDisassembly"; lstDisassembly.Size = new Size(252, 264); @@ -180,7 +181,7 @@ // lstStack // lstStack.FormattingEnabled = true; - lstStack.Location = new Point(779, 11); + lstStack.Location = new Point(823, 8); lstStack.Margin = new Padding(2); lstStack.Name = "lstStack"; lstStack.Size = new Size(130, 264); @@ -189,7 +190,7 @@ // label1 // label1.AutoSize = true; - label1.Location = new Point(289, 284); + label1.Location = new Point(568, 298); label1.Name = "label1"; label1.Size = new Size(81, 20); label1.TabIndex = 19; @@ -197,7 +198,7 @@ // // txtBreakpoint // - txtBreakpoint.Location = new Point(376, 281); + txtBreakpoint.Location = new Point(655, 295); txtBreakpoint.Name = "txtBreakpoint"; txtBreakpoint.Size = new Size(125, 27); txtBreakpoint.TabIndex = 20; @@ -234,7 +235,7 @@ // lblIff1 // lblIff1.AutoSize = true; - lblIff1.Location = new Point(88, 298); + lblIff1.Location = new Point(567, 411); lblIff1.Name = "lblIff1"; lblIff1.Size = new Size(35, 20); lblIff1.TabIndex = 24; @@ -243,7 +244,7 @@ // lblIff2 // lblIff2.AutoSize = true; - lblIff2.Location = new Point(88, 345); + lblIff2.Location = new Point(567, 458); lblIff2.Name = "lblIff2"; lblIff2.Size = new Size(35, 20); lblIff2.TabIndex = 25; @@ -252,7 +253,7 @@ // lblIE // lblIE.AutoSize = true; - lblIE.Location = new Point(88, 397); + lblIE.Location = new Point(568, 370); lblIE.Name = "lblIE"; lblIE.Size = new Size(109, 20); lblIE.TabIndex = 26; @@ -260,7 +261,7 @@ // // btnReset // - btnReset.Location = new Point(372, 313); + btnReset.Location = new Point(651, 327); btnReset.Margin = new Padding(2); btnReset.Name = "btnReset"; btnReset.Size = new Size(132, 27); @@ -278,7 +279,7 @@ // lblFrames // lblFrames.AutoSize = true; - lblFrames.Location = new Point(538, 320); + lblFrames.Location = new Point(568, 651); lblFrames.Margin = new Padding(2, 0, 2, 0); lblFrames.Name = "lblFrames"; lblFrames.Size = new Size(124, 20); @@ -288,7 +289,7 @@ // lblFPS // lblFPS.AutoSize = true; - lblFPS.Location = new Point(630, 397); + lblFPS.Location = new Point(660, 728); lblFPS.Margin = new Padding(2, 0, 2, 0); lblFPS.Name = "lblFPS"; lblFPS.Size = new Size(32, 20); @@ -298,18 +299,29 @@ // lblFrameTime // lblFrameTime.AutoSize = true; - lblFrameTime.Location = new Point(575, 356); + lblFrameTime.Location = new Point(605, 687); lblFrameTime.Margin = new Padding(2, 0, 2, 0); lblFrameTime.Name = "lblFrameTime"; lblFrameTime.Size = new Size(87, 20); lblFrameTime.TabIndex = 30; lblFrameTime.Text = "Frame Time"; // + // richTextBox1 + // + richTextBox1.Enabled = false; + richTextBox1.Location = new Point(568, 500); + richTextBox1.Name = "richTextBox1"; + richTextBox1.ReadOnly = true; + richTextBox1.Size = new Size(304, 113); + richTextBox1.TabIndex = 32; + richTextBox1.Text = "ZX Spectrum 48K Memory Map:\n0x0000 - 0x3FFF: ROM (16KB)\n0x4000 - 0x57FF: Display File (Screen Pixels)\n0x5800 - 0x5AFF: Colour Attributes\n0x5B00 - 0xFFFF: General Purpose RAM"; + // // DebuggerForm // AutoScaleDimensions = new SizeF(8F, 20F); AutoScaleMode = AutoScaleMode.Font; - ClientSize = new Size(928, 454); + ClientSize = new Size(965, 990); + Controls.Add(richTextBox1); Controls.Add(lblFrameTime); Controls.Add(lblFPS); Controls.Add(lblFrames); @@ -370,6 +382,7 @@ private Label lblFrames; private Label lblFPS; private Label lblFrameTime; + private RichTextBox richTextBox1; //private TextBox textBox4; } } \ No newline at end of file diff --git a/Desktop/DebuggerForm.cs b/Desktop/DebuggerForm.cs index df416af..51fbfcf 100644 --- a/Desktop/DebuggerForm.cs +++ b/Desktop/DebuggerForm.cs @@ -88,6 +88,7 @@ namespace Desktop private void UpdateMemoryView() { + int count = 40; // Try to parse the hex string the user typed in if (!ushort.TryParse(txtMemoryStart.Text, System.Globalization.NumberStyles.HexNumber, null, out ushort startAddress)) { @@ -98,7 +99,7 @@ namespace Desktop StringBuilder sb = new StringBuilder(); // Read 100 bytes (or roughly 6 lines of 16 bytes) - for (int line = 0; line < 7; line++) + for (int line = 0; line < count; line++) { ushort currentAddr = (ushort)(startAddress + (line * 16)); @@ -246,8 +247,8 @@ namespace Desktop instructionLength = 2; break; case 0x17: // RLA - mnemonic = "RLA"; - instructionLength = 1; + mnemonic = "RLA"; + instructionLength = 1; break; case 0x18: sbyte dUnconditional = (sbyte)_memoryBus.Read((ushort)(currentPc + 1)); @@ -266,7 +267,8 @@ namespace Desktop mnemonic = $"LD E, 0x{val1E:X2}"; instructionLength = 2; break; - case 0x1F: mnemonic = $"RRA"; + case 0x1F: + mnemonic = $"RRA"; break; case 0x20: sbyte jrOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1)); @@ -295,8 +297,8 @@ namespace Desktop instructionLength = 2; break; case 0x27: // DAA - mnemonic = "DAA"; - instructionLength = 1; + mnemonic = "DAA"; + instructionLength = 1; break; case 0x28: sbyte jrZOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1)); @@ -462,10 +464,10 @@ namespace Desktop case 0x8D: case 0x8E: case 0x8F: - string[] registers = { "B", "C", "D", "E", "H", "L", "(HL)", "A" }; - mnemonic = $"ADC A, {registers[opcode - 0x88]}"; - instructionLength = 1; - break; + string[] registers = { "B", "C", "D", "E", "H", "L", "(HL)", "A" }; + mnemonic = $"ADC A, {registers[opcode - 0x88]}"; + instructionLength = 1; + break; // --- SUB r --- case 0x90: mnemonic = "SUB B"; break; case 0x91: mnemonic = "SUB C"; break; @@ -524,7 +526,7 @@ namespace Desktop case 0xBC: mnemonic = "CP H"; break; case 0xBD: mnemonic = "CP L"; break; case 0xBE: mnemonic = "CP (HL)"; break; - case 0xBF: mnemonic = "CP A"; break; + case 0xBF: mnemonic = "CP A"; break; case 0xC1: mnemonic = "POP BC"; break; case 0xC2: case 0xCA: @@ -690,9 +692,9 @@ namespace Desktop mnemonic = "RET C"; break; case 0xDB: // IN A, (n) - n = _memoryBus.Read((ushort)(currentPc + 1)); - mnemonic = $"IN A, (0x{n:X2})"; - instructionLength = 2; + n = _memoryBus.Read((ushort)(currentPc + 1)); + mnemonic = $"IN A, (0x{n:X2})"; + instructionLength = 2; break; case 0xDD: { diff --git a/Desktop/Form1.Designer.cs b/Desktop/Form1.Designer.cs index 99d3316..3c35577 100644 --- a/Desktop/Form1.Designer.cs +++ b/Desktop/Form1.Designer.cs @@ -47,6 +47,7 @@ debuggerToolStripMenuItem = new ToolStripMenuItem(); optionsToolStripMenuItem = new ToolStripMenuItem(); HighSpeedToolStripMenuItem = new ToolStripMenuItem(); + fastLoadToolStripMenuItem = new ToolStripMenuItem(); playTapeToolStripMenuItem = new ToolStripMenuItem(); menuStrip1.SuspendLayout(); SuspendLayout(); @@ -73,7 +74,7 @@ // openToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { includedToolStripMenuItem, tAPToolStripMenuItem, sNAToolStripMenuItem }); openToolStripMenuItem.Name = "openToolStripMenuItem"; - openToolStripMenuItem.Size = new Size(224, 26); + openToolStripMenuItem.Size = new Size(188, 26); openToolStripMenuItem.Text = "Open"; // // includedToolStripMenuItem @@ -112,14 +113,14 @@ // saveSnapshotToolStripMenuItem // saveSnapshotToolStripMenuItem.Name = "saveSnapshotToolStripMenuItem"; - saveSnapshotToolStripMenuItem.Size = new Size(224, 26); + saveSnapshotToolStripMenuItem.Size = new Size(188, 26); saveSnapshotToolStripMenuItem.Text = "Save Snapshot"; saveSnapshotToolStripMenuItem.Click += SaveSNAMenuItem_Click; // // exitToolStripMenuItem // exitToolStripMenuItem.Name = "exitToolStripMenuItem"; - exitToolStripMenuItem.Size = new Size(224, 26); + exitToolStripMenuItem.Size = new Size(188, 26); exitToolStripMenuItem.Text = "Exit"; exitToolStripMenuItem.Click += btnExit_Click; // @@ -174,7 +175,7 @@ // // optionsToolStripMenuItem // - optionsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { HighSpeedToolStripMenuItem }); + optionsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { HighSpeedToolStripMenuItem, fastLoadToolStripMenuItem }); optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; optionsToolStripMenuItem.Size = new Size(75, 24); optionsToolStripMenuItem.Text = "Options"; @@ -182,10 +183,19 @@ // HighSpeedToolStripMenuItem // HighSpeedToolStripMenuItem.Name = "HighSpeedToolStripMenuItem"; - HighSpeedToolStripMenuItem.Size = new Size(170, 26); + HighSpeedToolStripMenuItem.Size = new Size(224, 26); HighSpeedToolStripMenuItem.Text = "High Speed"; HighSpeedToolStripMenuItem.Click += btnHighSpeedToggle_Click; // + // fastLoadToolStripMenuItem + // + fastLoadToolStripMenuItem.Checked = true; + fastLoadToolStripMenuItem.CheckState = CheckState.Checked; + fastLoadToolStripMenuItem.Name = "fastLoadToolStripMenuItem"; + fastLoadToolStripMenuItem.Size = new Size(224, 26); + fastLoadToolStripMenuItem.Text = "Fast Loading"; + fastLoadToolStripMenuItem.Click += fastLoadToolStripMenuItem_Click; + // // playTapeToolStripMenuItem // playTapeToolStripMenuItem.Name = "playTapeToolStripMenuItem"; @@ -230,5 +240,6 @@ private ToolStripMenuItem sNAToolStripMenuItem1; private ToolStripMenuItem saveSnapshotToolStripMenuItem; private ToolStripMenuItem playTapeToolStripMenuItem; + private ToolStripMenuItem fastLoadToolStripMenuItem; } } diff --git a/Desktop/Form1.cs b/Desktop/Form1.cs index ff68cfc..6a6decf 100644 --- a/Desktop/Form1.cs +++ b/Desktop/Form1.cs @@ -30,7 +30,9 @@ namespace Desktop public double FrameTime = 0; public bool highSpeed = false; public bool tapeLoaded = false; + public bool tapePlaying = false; private volatile bool _pendingReset = false; + private bool _enableFastLoad = true; // Comment to push a new commit public Form1() @@ -57,6 +59,8 @@ namespace Desktop _memoryBus.LoadRom(romData); _cpu = new Z80(_memoryBus, _simpleIoBus); _cpu.WaitStateCallback = _ula.GetContentionDelay; + fastLoadToolStripMenuItem.Checked = _enableFastLoad; + } catch (Exception ex) @@ -118,10 +122,10 @@ namespace Desktop long tStatesBefore = _cpu.TotalTStates; // --- HARDWARE INTERCEPTS --- - if ((_cpu.PC == 0x0556 || _cpu.PC == 0x0558) && _tapManager.HasBlocks) + if (_enableFastLoad && _cpu.PC == 0x0556 && _tapManager.HasBlocks) { HandleInstantTapeLoad(); - _cpu.TotalTStates += 100; // Charge some arbitrary time for the fast load + _cpu.TotalTStates += 100; } // --- Execute Instruction --- @@ -302,37 +306,34 @@ namespace Desktop private void PopulateIncludedTapsMenu() { - // 1. Get the current assembly (your .exe) Assembly assembly = Assembly.GetExecutingAssembly(); - - // 2. Find all embedded resources string[] resourceNames = assembly.GetManifestResourceNames(); foreach (string resourceName in resourceNames) { - // Check if it is a TAP file in our TestRoms folder - // (Embedded resources use dot-notation, e.g., "Desktop.TestRoms.ZEXALL.TAP") if (resourceName.Contains("Desktop.ROMS.TAP.") && resourceName.EndsWith(".TAP", StringComparison.OrdinalIgnoreCase)) { - // Clean up the name for the menu (e.g., "Desktop.TestRoms.ZEXALL.TAP" -> "ZEXALL") + string[] parts = resourceName.Split('.'); string displayName = parts[parts.Length - 2]; - - // Create the new menu item ToolStripMenuItem item = new ToolStripMenuItem(displayName); - // Store the full internal path in the Tag so we know what to load when clicked item.Tag = resourceName; - // Wire up the click event item.Click += IncludedTapMenuItem_Click; - // Add it to the "Open Included..." dropdown tAPToolStripMenuItem1.DropDownItems.Add(item); } } } + private void fastLoadToolStripMenuItem_Click(object sender, EventArgs e) + { + this.fastLoadToolStripMenuItem.Checked = !this.fastLoadToolStripMenuItem.Checked; + + _enableFastLoad = this.fastLoadToolStripMenuItem.Checked; + } + private void IncludedTapMenuItem_Click(object? sender, EventArgs e) { if (sender is ToolStripMenuItem item && item.Tag is string resourceName) @@ -357,7 +358,7 @@ namespace Desktop // Feed it directly to your existing TapManager! _tapManager.LoadTapData(tapBytes); tapeLoaded = true; - _tapManager.Play(); + //_tapManager.Play(); } } } @@ -488,7 +489,7 @@ namespace Desktop byte[] tapBytes = File.ReadAllBytes(ofd.FileName); _tapManager.LoadTapData(tapBytes); tapeLoaded = true; - _tapManager.Play(); + //_tapManager.Play(); } } _isPaused = false; @@ -643,11 +644,13 @@ namespace Desktop { playTapeToolStripMenuItem.Text = "Stop Tape"; _tapManager.Play(); + tapePlaying = true; } else { playTapeToolStripMenuItem.Text = "Play Tape"; _tapManager.Stop(); + tapePlaying = false; } }