Skip to content

Z80 ​

The Z80 format stores a complete snapshot of a ZX Spectrum's state — CPU registers, memory contents, and hardware settings. Three versions exist: V1 (48K only, always compressed), V2 and V3 (48K and 128K, with optional compression and extended hardware information).

Details about the Z80 format can be found at https://worldofspectrum.org/faq/reference/z80format.htm.

API ​

ClassDescription
Z80FormatSingleton format for reading and writing Z80 snapshots.
Z80FileBase class for all Z80 snapshot files.
Z80V1FileVersion 1 snapshot (48K).
Z80V2FileVersion 2 snapshot (48K and 128K).
Z80V3FileVersion 3 snapshot (48K and 128K).
Z80V1HeaderHeader for V1 snapshots.
Z80V2HeaderHeader for V2 snapshots.
Z80V3HeaderHeader for V3 snapshots.

Reading and Writing ​

c#
// Read
using var stream = File.OpenRead("snapshot.z80");
Z80File z80 = Z80Format.Instance.Read(stream);

// Write
using var output = File.Create("output.z80");
z80.Write(output);

The format version is detected automatically on read. The returned object is a Z80V1File, Z80V2File, or Z80V3File depending on the file.

Accessing Registers ​

All Z80 file types expose a Registers property providing the CPU register state at the time of the snapshot:

c#
var regs = z80.Registers;
Console.WriteLine($"PC: 0x{regs.PC:X4}  SP: 0x{regs.SP:X4}");
Console.WriteLine($"AF: 0x{regs.AF:X4}  BC: 0x{regs.BC:X4}");

// Shadow registers (not available on NEX snapshots):
var shadow = regs.Shadow;
Console.WriteLine($"AF': 0x{shadow.AF:X4}");

Creating Snapshots ​

Factory methods create a snapshot from a 64 KB memory buffer:

c#
byte[] memory = new byte[64 * 1024];
// ... populate memory ...

Z80V1File v1 = Z80V1File.Create48k(memory);
v1.Header.Registers.PC = 0x8000;

Z80V2File v2 = Z80V2File.Create48k(memory);
Z80V3File v3 = Z80V3File.Create48k(memory);

For 128K snapshots, Z80V2File.Create128k and Z80V3File.Create128k take exactly eight physical RAM banks, numbered 0–7, each containing 16384 bytes. They copy the supplied data; compression is enabled by default:

c#
ReadOnlyMemory<byte>[] banks = Enumerable.Range(0, 8)
    .Select(_ => (ReadOnlyMemory<byte>)new byte[16384]).ToArray();
// ... populate each physical bank ...
Z80V3File banked = Z80V3File.Create128k(banks, port7FFD: 0x10, compress: true);
banked.Registers.PC = 0x8000;
banked.Registers.SP = 0xBFFE;

The default $7FFD value is $10: 48K ROM, RAM bank 0, normal screen and unlocked paging. Registers and BASIC system variables are not initialized. Set PC, SP and any workspace required by the application, including BANKM if it uses that shadow. Header.Port7FFD exposes the saved paging latch. GetBank(number) returns uncompressed physical RAM independently of the selected bank.

RAM banks 0–7 use page numbers 3–10. V2 uses hardware code 3 for a plain 128K Spectrum; V3 uses code 4. These values and the paging-latch offset follow the Z80 format specification.

Loading Snapshot Memory ​

Use TryLoadInto to restore a snapshot's memory into a buffer:

c#
byte[] memory = new byte[64 * 1024];
z80.TryLoadInto(memory);

For a 128K snapshot this restores the visible mapping: bank 5 at $4000, bank 2 at $8000, and the bank selected by Header.Port7FFD at $C000. Other physical banks remain available through GetBank; the buffer's ROM area is unchanged.

Conversions ​

Z80 snapshots can be converted to SNA. A 128K conversion retains all eight RAM banks, CPU registers and $7FFD state, and requires exactly one page for each RAM bank. Additional ROM or peripheral memory pages are rejected rather than silently dropped. SNA cannot store Z80-specific metadata such as AY register state, frame timing or a separate IFF1 value; converting back sets IFF1 to the saved IFF2 value. See Reading, Writing and Converting.