From 968141056b71d5c47809d3a16e4849a403e5f182 Mon Sep 17 00:00:00 2001 From: Marc Parsons Date: Thu, 16 Apr 2026 14:40:05 +0100 Subject: [PATCH] Some minor changes and playing about --- Core/Cpu/Z80.cs | 19 ++++------- Core/Io/IO_Bus.cs | 43 +++++++++++++++++++++++++ Core/Io/SimpleIoBus.cs | 20 ------------ Core/Memory/MemoryBus.cs | 10 +++++- Desktop/48.rom | Bin 16384 -> 16384 bytes Desktop/48.rom.bak | Bin 0 -> 16384 bytes Desktop/DebuggerForm.cs | 22 +++++++------ Desktop/Form1.Designer.cs | 1 + Desktop/Form1.cs | 66 ++++++++++++++++++++++++++++++++++++-- 9 files changed, 135 insertions(+), 46 deletions(-) create mode 100644 Core/Io/IO_Bus.cs delete mode 100644 Core/Io/SimpleIoBus.cs create mode 100644 Desktop/48.rom.bak diff --git a/Core/Cpu/Z80.cs b/Core/Cpu/Z80.cs index 7ce3dec..d98ddac 100644 --- a/Core/Cpu/Z80.cs +++ b/Core/Cpu/Z80.cs @@ -1,5 +1,6 @@ using System; using Core.Interfaces; +using Core.Io; namespace Core.Cpu { @@ -38,12 +39,12 @@ namespace Core.Cpu // The Memory Bus private readonly IMemory _memory; - private readonly IIoBus _ioBus; + private readonly IO_Bus _simpleIoBus; - public Z80(IMemory memory, IIoBus ioBus) + public Z80(IMemory memory, IO_Bus ioBus) { _memory = memory; - _ioBus = ioBus; + _simpleIoBus = ioBus; Reset(); } @@ -122,15 +123,7 @@ namespace Core.Cpu // Placeholder for your hardware I/O private byte ReadPort(ushort portAddress) { - // If the port is 0xFE, the ROM is asking for keyboard/tape/ULA data! - // For now, we will return 0xFF (meaning "No keys are currently pressed") - if ((portAddress & 0xFF) == 0xFE) - { - return 0xFF; - } - - // Default floating bus return - return 0xFF; + return _simpleIoBus.ReadPort(portAddress); } public int Step() @@ -1086,7 +1079,7 @@ namespace Core.Cpu // The Z80 puts 'A' on the top 8 bits, and 'n' on the bottom 8 bits of the port address ushort portAddress = (ushort)((AF.High << 8) | portOffset); - _ioBus.Write(portAddress, AF.High); + _simpleIoBus.WritePort(portAddress, AF.High); return 11; case 0xd5: //push bc diff --git a/Core/Io/IO_Bus.cs b/Core/Io/IO_Bus.cs new file mode 100644 index 0000000..b473df8 --- /dev/null +++ b/Core/Io/IO_Bus.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; +using Core.Interfaces; + +namespace Core.Io +{ + public class IO_Bus +{ + // 8 rows representing the Spectrum keyboard matrix. Default to 0xFF (unpressed). + public byte[] KeyboardRows = new byte[8] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + + public byte ReadPort(ushort portAddress) + { + // The Spectrum ULA responds to any even port address (where the lowest bit is 0) + if ((portAddress & 0x01) == 0) + { + byte highByte = (byte)(portAddress >> 8); // The B register! + byte result = 0xFF; // Start assuming no keys are pressed + + // The ROM pulls a specific bit low (0) in the high byte to request a row. + // Sometimes it pulls multiple bits low to scan multiple rows at once, so we AND the results. + if ((highByte & 0x01) == 0) result &= KeyboardRows[0]; // 0xFE: CAPS, Z, X, C, V + if ((highByte & 0x02) == 0) result &= KeyboardRows[1]; // 0xFD: A, S, D, F, G + if ((highByte & 0x04) == 0) result &= KeyboardRows[2]; // 0xFB: Q, W, E, R, T + if ((highByte & 0x08) == 0) result &= KeyboardRows[3]; // 0xF7: 1, 2, 3, 4, 5 + if ((highByte & 0x10) == 0) result &= KeyboardRows[4]; // 0xEF: 0, 9, 8, 7, 6 + if ((highByte & 0x20) == 0) result &= KeyboardRows[5]; // 0xDF: P, O, I, U, Y + if ((highByte & 0x40) == 0) result &= KeyboardRows[6]; // 0xBF: ENTER, L, K, J, H + if ((highByte & 0x80) == 0) result &= KeyboardRows[7]; // 0x7F: SPACE, SYM, M, N, B + + // The top 3 bits (5, 6, 7) are unused by the keyboard and usually return 1 on a real Spectrum + return (byte)(result | 0xE0); + } + + // Return 0xFF for unhandled ports + return 0xFF; + } + + public void WritePort(ushort portAddress, byte portValue) + { + + } +} +} \ No newline at end of file diff --git a/Core/Io/SimpleIoBus.cs b/Core/Io/SimpleIoBus.cs deleted file mode 100644 index dbb90d9..0000000 --- a/Core/Io/SimpleIoBus.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Diagnostics; -using Core.Interfaces; - -namespace Core.Io -{ - public class SimpleIoBus : IIoBus - { - public byte Read(ushort port) - { - // If the CPU reads an unconnected port, the Z80 usually sees 0xFF - return 0xFF; - } - - public void Write(ushort port, byte value) - { - // For now, let's just log it to the Visual Studio Output window - Debug.WriteLine($"Hardware I/O Write -> Port: 0x{port:X4}, Value: 0x{value:X2}"); - } - } -} \ No newline at end of file diff --git a/Core/Memory/MemoryBus.cs b/Core/Memory/MemoryBus.cs index bf1595e..43d613a 100644 --- a/Core/Memory/MemoryBus.cs +++ b/Core/Memory/MemoryBus.cs @@ -35,12 +35,20 @@ namespace Core.Memory public void CrapRAMData() { Random random = new Random(); - for (int i = 0x4000; i < 0x5AFF; i++) + for (int i = 0x4000; i < 0xFFFF; i++) { _memory[i] = (byte)random.Next(0x00, 0xFF); } } + public void CleanRAMData() + { + for (int i = 0x4000; i < 0xFFFF; i++) + { + _memory[i] = 0x00; + } + } + // Load the ROM file public void LoadRom(byte[] romData) { diff --git a/Desktop/48.rom b/Desktop/48.rom index 4d6895e0bbf3fa543f192a66a297192b3c969ac9..752c38ae4ed8da9e3eee9a92304741278b7ee8c5 100644 GIT binary patch delta 41 wcmZo@U~Fh$++Zy#Wn^GvrVx-=RGgnztPqr1oSImaoT1=T@`Pb?sOV}f02QhY@Bjb+ delta 41 wcmZo@U~Fh$++Zy#WoT((q!65$mzq@TAZ3#l$@d9Q}SeUsOV}f02gNtNdN!< diff --git a/Desktop/48.rom.bak b/Desktop/48.rom.bak new file mode 100644 index 0000000000000000000000000000000000000000..ced65a8ba779af6b013551eae658d1cfc2147a47 GIT binary patch literal 16384 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 YNDjAXV4dH?_b literal 0 HcmV?d00001 diff --git a/Desktop/DebuggerForm.cs b/Desktop/DebuggerForm.cs index b15862e..07d98a1 100644 --- a/Desktop/DebuggerForm.cs +++ b/Desktop/DebuggerForm.cs @@ -53,7 +53,7 @@ namespace Desktop private async void btnRun_Click(object sender, EventArgs e) { - // If it is already running, this button acts as a STOP button + //Stops if (_isRunning) { _isRunning = false; @@ -61,7 +61,7 @@ namespace Desktop return; } - // --- NEW: Parse the Breakpoint --- + //Parse the Breakpoint if (!string.IsNullOrWhiteSpace(txtBreakpoint.Text)) { if (ushort.TryParse(txtBreakpoint.Text, System.Globalization.NumberStyles.HexNumber, null, out ushort parsedBp)) @@ -76,18 +76,14 @@ namespace Desktop } else { - _breakpoint = null; // No text means no breakpoint + _breakpoint = null; } - // --------------------------------- // Start the run state _isRunning = true; btnRun.Text = "Stop"; - - - // Fire up a background thread - // Fire up a background thread + //Background thread await Task.Run(() => { try @@ -111,6 +107,13 @@ namespace Desktop // --- Execute Instruction --- _cpu.Step(); + //if (_cpu.TotalTStates % 1000 == 0) + //{ + // this.Invoke((MethodInvoker)delegate + // { + // UpdateDisplay(); + // }); + //} // --- Check for End of Frame --- if (_cpu.TotalTStates >= nextFrameTargetTStates) @@ -164,8 +167,7 @@ namespace Desktop } }); - // Whether it stopped because of a breakpoint, a crash, or the user clicking "Stop", - // we MUST update the UI when the background thread finishes! + //update the UI when the background thread finishes btnRun.Text = "Run"; UpdateDisplay(); } diff --git a/Desktop/Form1.Designer.cs b/Desktop/Form1.Designer.cs index ced990d..389d04b 100644 --- a/Desktop/Form1.Designer.cs +++ b/Desktop/Form1.Designer.cs @@ -48,6 +48,7 @@ AutoScaleMode = AutoScaleMode.Font; ClientSize = new Size(791, 596); Controls.Add(picScreen); + KeyPreview = true; Name = "Form1"; Text = "Parsons Sinclair ZX Spectrum 48K - 2026"; ((System.ComponentModel.ISupportInitialize)picScreen).EndInit(); diff --git a/Desktop/Form1.cs b/Desktop/Form1.cs index dea3f91..caa947e 100644 --- a/Desktop/Form1.cs +++ b/Desktop/Form1.cs @@ -13,7 +13,7 @@ namespace Desktop { private Z80 _cpu = null!; private MemoryBus _memoryBus = null!; - private SimpleIoBus _simpleIoBus = null!; + private IO_Bus _simpleIoBus = null!; // The 16 physical colors of the ZX Spectrum (ARGB format) private readonly int[] SpectrumColors = new int[] @@ -50,7 +50,7 @@ namespace Desktop try { _memoryBus = new MemoryBus(); - _simpleIoBus = new SimpleIoBus(); + _simpleIoBus = new IO_Bus(); _memoryBus.CrapRAMData(); byte[] romData = RomLoader.Load("48.rom"); @@ -120,5 +120,67 @@ namespace Desktop if (picScreen.Image != null) picScreen.Image.Dispose(); picScreen.Image = bmp; } + + // Helper method to update the IO Bus state + private void UpdateMatrix(int row, int col, bool isPressed) + { + if (isPressed) + { + // Clear the bit to 0 (Active-Low = Pressed) + _simpleIoBus.KeyboardRows[row] &= (byte)~(1 << col); + } + else + { + // Set the bit back to 1 (Unpressed) + _simpleIoBus.KeyboardRows[row] |= (byte)(1 << col); + } + } + + // Hook this to Form1's KeyDown event + protected override void OnKeyDown(KeyEventArgs e) + { + HandleKey(e.KeyCode, true); + base.OnKeyDown(e); + } + + // Hook this to Form1's KeyUp event + protected override void OnKeyUp(KeyEventArgs e) + { + HandleKey(e.KeyCode, false); + base.OnKeyUp(e); + } + + private void HandleKey(Keys key, bool isPressed) + { + switch (key) + { + // Row 6: ENTER, L, K, J, H + case Keys.Enter: UpdateMatrix(6, 0, isPressed); break; + case Keys.L: UpdateMatrix(6, 1, isPressed); break; + case Keys.K: UpdateMatrix(6, 2, isPressed); break; + case Keys.J: UpdateMatrix(6, 3, isPressed); break; + case Keys.H: UpdateMatrix(6, 4, isPressed); break; + + // Row 7: SPACE, SYM SHIFT, M, N, B + case Keys.Space: UpdateMatrix(7, 0, isPressed); break; + case Keys.M: UpdateMatrix(7, 2, isPressed); break; + case Keys.N: UpdateMatrix(7, 3, isPressed); break; + case Keys.B: UpdateMatrix(7, 4, isPressed); break; + + // Row 1: A, S, D, F, G + case Keys.A: UpdateMatrix(1, 0, isPressed); break; + case Keys.S: UpdateMatrix(1, 1, isPressed); break; + case Keys.D: UpdateMatrix(1, 2, isPressed); break; + case Keys.F: UpdateMatrix(1, 3, isPressed); break; + case Keys.G: UpdateMatrix(1, 4, isPressed); break; + + // Map the rest of the alphabet and numbers here as you need them! + } + } + + private void Form1_KeyDown(object sender, KeyEventArgs e) + { + + } } } \ No newline at end of file