Can somewhat load from audio

This commit is contained in:
2026-04-28 20:09:03 +01:00
parent 38bef38f96
commit ae685eabd6
7 changed files with 127 additions and 105 deletions

View File

@@ -1352,6 +1352,10 @@ namespace Core.Cpu
case 0x4D: // RETI Does not affect IFF1 or IFF2 case 0x4D: // RETI Does not affect IFF1 or IFF2
PC = Pop(); PC = Pop();
return 14; return 14;
case 0x51: // OUT (C), D
// BC.Word goes to the address bus, D (DE.High) goes to the data bus
_simpleIoBus.WritePort(BC.Word, DE.High);
return 12; // 2 M-cycles, 12 T-States
case 0x53: // LD (nn), DE case 0x53: // LD (nn), DE
ushort dest53 = FetchWord(); ushort dest53 = FetchWord();
WriteMemory(dest53, DE.Low); WriteMemory(dest53, DE.Low);
@@ -1372,6 +1376,10 @@ namespace Core.Cpu
AF.Low = flags58; AF.Low = flags58;
return 12; return 12;
case 0x59: // OUT (C), E
// BC.Word goes to the address bus, E (DE.Low) goes to the data bus
_simpleIoBus.WritePort(BC.Word, DE.Low);
return 12; // 2 M-cycles, 12 T-States
case 0x5B: // LD DE, (nn) case 0x5B: // LD DE, (nn)
ushort src5B = FetchWord(); ushort src5B = FetchWord();
DE.Low = ReadMemory(src5B); DE.Low = ReadMemory(src5B);

View File

@@ -19,7 +19,7 @@ namespace Core.Io
public byte ReadPort(ushort portAddress) public byte ReadPort(ushort portAddress)
{ {
// The Spectrum ULA responds to any even port address (where the lowest bit is 0) // The Spectrum ULA responds to any even port address (where the lowest bit is 0)
if ((portAddress & 0x01) == 0) if ((portAddress & 0x01) == 0) //Port 0xFE)
{ {
byte highByte = (byte)(portAddress >> 8); // The B register! byte highByte = (byte)(portAddress >> 8); // The B register!
byte result = 0xFF; // Start assuming no keys are pressed byte result = 0xFF; // Start assuming no keys are pressed
@@ -40,11 +40,17 @@ namespace Core.Io
//return result; //return result;
// The top 3 bits (5, 6, 7) are unused by the keyboard and usually return 1 on a real Spectrum // 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 (byte)(result | 0xA0);
}
// Kempston Joystick Port
if ((portAddress & 0xFF) == 0x1F)
{
return 0x00; // 0x00 means no joystick connected/no buttons pressed
} }
// Return 0xFF for unhandled ports // Return 0xFF for unhandled ports
return 0xFF; return 0x00;
} }
public void WritePort(ushort portAddress, byte portValue) public void WritePort(ushort portAddress, byte portValue)

View File

@@ -46,6 +46,11 @@ namespace Core.Io
} }
} }
public void Stop()
{
_state = TapeState.Idle;
}
private void LoadNextBlock() private void LoadNextBlock()
{ {
if (_blocks.Count == 0) if (_blocks.Count == 0)
@@ -142,7 +147,8 @@ namespace Core.Io
break; break;
case TapeState.Pause: case TapeState.Pause:
LoadNextBlock(); _state = TapeState.Idle;
//LoadNextBlock();
break; break;
} }
} }
@@ -157,54 +163,28 @@ namespace Core.Io
} }
// --- FAST LOAD METHODS (For ROM Hijack) --- // --- FAST LOAD METHODS (For ROM Hijack) ---
public byte[] GetNextBlock()
{
return _blocks.Count > 0 ? _blocks.Dequeue() : null;
}
public bool HasBlocks => _blocks.Count > 0;
}
}
//using System;
//using System.Collections.Generic;
//namespace Core.Io
//{
// public class TapManager
// {
// private Queue<byte[]> _blocks = new Queue<byte[]>();
// public void LoadTapData(byte[] fileData)
// {
// _blocks.Clear();
// int position = 0;
// while (position < fileData.Length)
// {
// // 1. Read the 16-bit block length (Little Endian)
// int blockLength = fileData[position] | (fileData[position + 1] << 8);
// position += 2;
// // 2. Extract the block payload
// byte[] blockData = new byte[blockLength];
// Array.Copy(fileData, position, blockData, 0, blockLength);
// position += blockLength;
// // 3. Queue it up
// _blocks.Enqueue(blockData);
// }
// }
//public byte[] GetNextBlock() //public byte[] GetNextBlock()
//{ //{
// return _blocks.Count > 0 ? _blocks.Dequeue() : null; // return _blocks.Count > 0 ? _blocks.Dequeue() : null;
//} //}
//public bool HasBlocks => _blocks.Count > 0; //public bool HasBlocks => _blocks.Count > 0;
// } // Change this line:
//} public bool HasBlocks => _blocks.Count > 0 || _currentBlock != null;
public byte[] GetNextBlock()
{
// If a block is loaded into the tape deck, yank it immediately
if (_currentBlock != null)
{
byte[] blockToReturn = _currentBlock;
_state = TapeState.Idle; // Ensure the tape deck is stopped
_currentBlock = null;
return blockToReturn;
}
// Otherwise, pull directly from the queue
return _blocks.Count > 0 ? _blocks.Dequeue() : null;
}
}
}

View File

@@ -266,6 +266,8 @@ namespace Desktop
mnemonic = $"LD E, 0x{val1E:X2}"; mnemonic = $"LD E, 0x{val1E:X2}";
instructionLength = 2; instructionLength = 2;
break; break;
case 0x1F: mnemonic = $"RRA";
break;
case 0x20: case 0x20:
sbyte jrOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1)); sbyte jrOffset = (sbyte)_memoryBus.Read((ushort)(currentPc + 1));
ushort destination = (ushort)(currentPc + 2 + jrOffset); ushort destination = (ushort)(currentPc + 2 + jrOffset);

View File

@@ -36,24 +36,25 @@
sNAToolStripMenuItem1 = new ToolStripMenuItem(); sNAToolStripMenuItem1 = new ToolStripMenuItem();
tAPToolStripMenuItem = new ToolStripMenuItem(); tAPToolStripMenuItem = new ToolStripMenuItem();
sNAToolStripMenuItem = new ToolStripMenuItem(); sNAToolStripMenuItem = new ToolStripMenuItem();
saveSnapshotToolStripMenuItem = new ToolStripMenuItem();
exitToolStripMenuItem = new ToolStripMenuItem(); exitToolStripMenuItem = new ToolStripMenuItem();
viewToolStripMenuItem = new ToolStripMenuItem();
debuggerToolStripMenuItem = new ToolStripMenuItem();
machineToolStripMenuItem = new ToolStripMenuItem(); machineToolStripMenuItem = new ToolStripMenuItem();
runToolStripMenuItem = new ToolStripMenuItem(); runToolStripMenuItem = new ToolStripMenuItem();
resetToolStripMenuItem = new ToolStripMenuItem(); resetToolStripMenuItem = new ToolStripMenuItem();
stepToolStripMenuItem = new ToolStripMenuItem(); stepToolStripMenuItem = new ToolStripMenuItem();
resetToolStripMenuItem1 = new ToolStripMenuItem(); resetToolStripMenuItem1 = new ToolStripMenuItem();
viewToolStripMenuItem = new ToolStripMenuItem();
debuggerToolStripMenuItem = new ToolStripMenuItem();
optionsToolStripMenuItem = new ToolStripMenuItem(); optionsToolStripMenuItem = new ToolStripMenuItem();
HighSpeedToolStripMenuItem = new ToolStripMenuItem(); HighSpeedToolStripMenuItem = new ToolStripMenuItem();
saveSnapshotToolStripMenuItem = new ToolStripMenuItem(); playTapeToolStripMenuItem = new ToolStripMenuItem();
menuStrip1.SuspendLayout(); menuStrip1.SuspendLayout();
SuspendLayout(); SuspendLayout();
// //
// menuStrip1 // menuStrip1
// //
menuStrip1.ImageScalingSize = new Size(24, 24); menuStrip1.ImageScalingSize = new Size(24, 24);
menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, machineToolStripMenuItem, viewToolStripMenuItem, optionsToolStripMenuItem }); menuStrip1.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, machineToolStripMenuItem, viewToolStripMenuItem, optionsToolStripMenuItem, playTapeToolStripMenuItem });
menuStrip1.Location = new Point(0, 0); menuStrip1.Location = new Point(0, 0);
menuStrip1.Name = "menuStrip1"; menuStrip1.Name = "menuStrip1";
menuStrip1.Padding = new Padding(5, 2, 0, 2); menuStrip1.Padding = new Padding(5, 2, 0, 2);
@@ -108,6 +109,13 @@
sNAToolStripMenuItem.Text = "SNA"; sNAToolStripMenuItem.Text = "SNA";
sNAToolStripMenuItem.Click += openSNAToolStripMenuItem_Click; sNAToolStripMenuItem.Click += openSNAToolStripMenuItem_Click;
// //
// saveSnapshotToolStripMenuItem
//
saveSnapshotToolStripMenuItem.Name = "saveSnapshotToolStripMenuItem";
saveSnapshotToolStripMenuItem.Size = new Size(224, 26);
saveSnapshotToolStripMenuItem.Text = "Save Snapshot";
saveSnapshotToolStripMenuItem.Click += SaveSNAMenuItem_Click;
//
// exitToolStripMenuItem // exitToolStripMenuItem
// //
exitToolStripMenuItem.Name = "exitToolStripMenuItem"; exitToolStripMenuItem.Name = "exitToolStripMenuItem";
@@ -115,6 +123,41 @@
exitToolStripMenuItem.Text = "Exit"; exitToolStripMenuItem.Text = "Exit";
exitToolStripMenuItem.Click += btnExit_Click; exitToolStripMenuItem.Click += btnExit_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;
//
// viewToolStripMenuItem // viewToolStripMenuItem
// //
viewToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { debuggerToolStripMenuItem }); viewToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { debuggerToolStripMenuItem });
@@ -129,41 +172,6 @@
debuggerToolStripMenuItem.Text = "Debugger"; debuggerToolStripMenuItem.Text = "Debugger";
debuggerToolStripMenuItem.Click += openDebuggerToolStripMenuItem_Click; 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(224, 26);
runToolStripMenuItem.Text = "Run";
runToolStripMenuItem.Click += btnRun_Click;
//
// resetToolStripMenuItem
//
resetToolStripMenuItem.Name = "resetToolStripMenuItem";
resetToolStripMenuItem.Size = new Size(224, 26);
resetToolStripMenuItem.Text = "Pause";
resetToolStripMenuItem.Click += btnPause_Click;
//
// stepToolStripMenuItem
//
stepToolStripMenuItem.Name = "stepToolStripMenuItem";
stepToolStripMenuItem.Size = new Size(224, 26);
stepToolStripMenuItem.Text = "Step";
stepToolStripMenuItem.Click += btnStep_Click;
//
// resetToolStripMenuItem1
//
resetToolStripMenuItem1.Name = "resetToolStripMenuItem1";
resetToolStripMenuItem1.Size = new Size(224, 26);
resetToolStripMenuItem1.Text = "Reset";
resetToolStripMenuItem1.Click += btnReset_Click;
//
// optionsToolStripMenuItem // optionsToolStripMenuItem
// //
optionsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { HighSpeedToolStripMenuItem }); optionsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { HighSpeedToolStripMenuItem });
@@ -178,12 +186,12 @@
HighSpeedToolStripMenuItem.Text = "High Speed"; HighSpeedToolStripMenuItem.Text = "High Speed";
HighSpeedToolStripMenuItem.Click += btnHighSpeedToggle_Click; HighSpeedToolStripMenuItem.Click += btnHighSpeedToggle_Click;
// //
// saveSnapshotToolStripMenuItem // playTapeToolStripMenuItem
// //
saveSnapshotToolStripMenuItem.Name = "saveSnapshotToolStripMenuItem"; playTapeToolStripMenuItem.Name = "playTapeToolStripMenuItem";
saveSnapshotToolStripMenuItem.Size = new Size(224, 26); playTapeToolStripMenuItem.Size = new Size(85, 24);
saveSnapshotToolStripMenuItem.Text = "Save Snapshot"; playTapeToolStripMenuItem.Text = "Play Tape";
saveSnapshotToolStripMenuItem.Click += SaveSNAMenuItem_Click; playTapeToolStripMenuItem.Click += playTapeToolStripMenuItem_Click;
// //
// Form1 // Form1
// //
@@ -221,5 +229,6 @@
private ToolStripMenuItem tAPToolStripMenuItem1; private ToolStripMenuItem tAPToolStripMenuItem1;
private ToolStripMenuItem sNAToolStripMenuItem1; private ToolStripMenuItem sNAToolStripMenuItem1;
private ToolStripMenuItem saveSnapshotToolStripMenuItem; private ToolStripMenuItem saveSnapshotToolStripMenuItem;
private ToolStripMenuItem playTapeToolStripMenuItem;
} }
} }

View File

@@ -118,7 +118,7 @@ namespace Desktop
long tStatesBefore = _cpu.TotalTStates; long tStatesBefore = _cpu.TotalTStates;
// --- HARDWARE INTERCEPTS --- // --- HARDWARE INTERCEPTS ---
if (_cpu.PC == 0x0556 && _tapManager.HasBlocks) if ((_cpu.PC == 0x0556 || _cpu.PC == 0x0558) && _tapManager.HasBlocks)
{ {
HandleInstantTapeLoad(); HandleInstantTapeLoad();
_cpu.TotalTStates += 100; // Charge some arbitrary time for the fast load _cpu.TotalTStates += 100; // Charge some arbitrary time for the fast load
@@ -357,6 +357,7 @@ namespace Desktop
// Feed it directly to your existing TapManager! // Feed it directly to your existing TapManager!
_tapManager.LoadTapData(tapBytes); _tapManager.LoadTapData(tapBytes);
tapeLoaded = true; tapeLoaded = true;
_tapManager.Play();
} }
} }
} }
@@ -487,6 +488,7 @@ namespace Desktop
byte[] tapBytes = File.ReadAllBytes(ofd.FileName); byte[] tapBytes = File.ReadAllBytes(ofd.FileName);
_tapManager.LoadTapData(tapBytes); _tapManager.LoadTapData(tapBytes);
tapeLoaded = true; tapeLoaded = true;
_tapManager.Play();
} }
} }
_isPaused = false; _isPaused = false;
@@ -634,5 +636,20 @@ namespace Desktop
case Keys.B: UpdateMatrix(7, 4, isPressed); break; case Keys.B: UpdateMatrix(7, 4, isPressed); break;
} }
} }
private void playTapeToolStripMenuItem_Click(object sender, EventArgs e)
{
if (playTapeToolStripMenuItem.Text == "Play Tape")
{
playTapeToolStripMenuItem.Text = "Stop Tape";
_tapManager.Play();
}
else
{
playTapeToolStripMenuItem.Text = "Play Tape";
_tapManager.Stop();
}
}
} }
} }

Binary file not shown.