WIP implementing TZX support

This commit is contained in:
2026-04-30 17:43:20 +01:00
parent 5c7ccc02ff
commit bf3d7d228a
5 changed files with 101 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Core.Io;
namespace Core.Io
{
@@ -7,6 +8,7 @@ namespace Core.Io
{
private Queue<byte[]> _blocks = new Queue<byte[]>();
private byte[] _currentBlock;
private List<TzxBlock> _tzxBlocks = new List<TzxBlock>();
// State Machine Tracking
private enum TapeState { Idle, Pilot, Sync1, Sync2, Data, Pause }
@@ -204,5 +206,13 @@ namespace Core.Io
_currentBlock = null;
return _blocks.Count > 0 ? _blocks.Dequeue() : null;
}
public void LoadTzxData(List<TzxBlock> blocks)
{
_tzxBlocks = blocks;
// Just to prove it works before we build the State Machine!
System.Diagnostics.Debug.WriteLine($"Successfully loaded {_tzxBlocks.Count} TZX blocks!");
}
}
}

24
Core/Io/TzxBlocks.cs Normal file
View File

@@ -0,0 +1,24 @@
using System;
namespace Core.Io
{
// The base class all future TZX blocks will inherit from
public abstract class TzxBlock
{
public abstract int BlockId { get; }
}
// ID 0x10: Standard Speed Data Block
public class StandardSpeedBlock : TzxBlock
{
public override int BlockId => 0x10;
// How long to pause the tape in milliseconds after this block loads
public ushort PauseAfterMs { get; set; }
public ushort DataLength { get; set; }
// The actual tape bytes
public byte[] Data { get; set; } = Array.Empty<byte>();
}
}

56
Core/Io/TzxParser.cs Normal file
View File

@@ -0,0 +1,56 @@
using Core.Io;
using System;
using System.Collections.Generic;
using System.IO;
namespace Core.Io
{
public class TzxParser
{
public static List<TzxBlock> Parse(byte[] fileBytes)
{
List<TzxBlock> blocks = new List<TzxBlock>();
using (MemoryStream ms = new MemoryStream(fileBytes))
using (BinaryReader br = new BinaryReader(ms))
{
// 1. Verify the 10-Byte Header
// Signature is "ZXTape!" followed by EOF (0x1A)
byte[] signature = br.ReadBytes(8);
string sigString = System.Text.Encoding.ASCII.GetString(signature);
if (sigString != "ZXTape!\x1A")
throw new Exception("Invalid TZX Signature! Is this a real TZX file?");
byte majorVersion = br.ReadByte();
byte minorVersion = br.ReadByte();
// 2. Read the blocks until we hit the end of the file
while (ms.Position < ms.Length)
{
byte blockId = br.ReadByte();
switch (blockId)
{
case 0x10: // Standard Speed Data
var stdBlock = new StandardSpeedBlock
{
PauseAfterMs = br.ReadUInt16(),
DataLength = br.ReadUInt16()
};
stdBlock.Data = br.ReadBytes(stdBlock.DataLength);
blocks.Add(stdBlock);
break;
// TODO: Add cases for 0x11 (Turbo), 0x12 (Tone), 0x13 (Pulses), etc.
default:
throw new NotImplementedException($"TZX Block ID 0x{blockId:X2} is not supported yet!");
}
}
}
return blocks;
}
}
}

View File

@@ -23,6 +23,7 @@ namespace Core
public IO_Bus IoBus { get; private set; }
public ULA Ula { get; private set; }
public TapManager TapeDeck { get; private set; }
public TzxParser _tzxParser { get; set; }
// Audio (If BeeperDevice is in Desktop, you may need to move it to Core,
// or inject it via an interface later. For now, assuming it's accessible).
@@ -276,6 +277,8 @@ namespace Core
ForceRet();
}
private void ForceRet()
{
byte pcLow = Memory.Read(Cpu.SP);