Fixed Plus 3 Snapshot saving and loading
This commit is contained in:
@@ -289,61 +289,17 @@ namespace Core
|
||||
// SNAPSHOT MANAGEMENT (.SNA)
|
||||
// ====================================================================
|
||||
|
||||
public void LoadSnapshot(byte[] snaData)
|
||||
{
|
||||
if (snaData.Length != 49179)
|
||||
throw new Exception("Invalid 48K SNA File Size!");
|
||||
|
||||
// 1. Load CPU Registers
|
||||
Cpu.I = snaData[0];
|
||||
Cpu.HL_Prime.Word = (ushort)(snaData[1] | (snaData[2] << 8));
|
||||
Cpu.DE_Prime.Word = (ushort)(snaData[3] | (snaData[4] << 8));
|
||||
Cpu.BC_Prime.Word = (ushort)(snaData[5] | (snaData[6] << 8));
|
||||
Cpu.AF_Prime.Word = (ushort)(snaData[7] | (snaData[8] << 8));
|
||||
|
||||
Cpu.HL.Word = (ushort)(snaData[9] | (snaData[10] << 8));
|
||||
Cpu.DE.Word = (ushort)(snaData[11] | (snaData[12] << 8));
|
||||
Cpu.BC.Word = (ushort)(snaData[13] | (snaData[14] << 8));
|
||||
Cpu.IY.Word = (ushort)(snaData[15] | (snaData[16] << 8));
|
||||
Cpu.IX.Word = (ushort)(snaData[17] | (snaData[18] << 8));
|
||||
|
||||
bool iff2 = (snaData[19] & 0x04) != 0;
|
||||
// Note: If IFF1/IFF2 have private setters in Z80.cs, you may need to
|
||||
// trigger an EI/DI instruction or temporarily unlock them.
|
||||
// Assuming they are public/internal for now based on previous code:
|
||||
|
||||
Cpu.R = snaData[20];
|
||||
Cpu.AF.Word = (ushort)(snaData[21] | (snaData[22] << 8));
|
||||
Cpu.SP = (ushort)(snaData[23] | (snaData[24] << 8));
|
||||
|
||||
// Set Interrupt Mode (Assuming you add a setter to Z80.InterruptMode if it's private)
|
||||
// Cpu.InterruptMode = snaData[25];
|
||||
|
||||
// THE BUG FIX: Restore the ULA Border Color!
|
||||
IoBus.BorderColourIndex = snaData[26];
|
||||
|
||||
// 2. Load the 48K RAM Dump
|
||||
for (int i = 0; i < 49152; i++)
|
||||
{
|
||||
Memory.Write((ushort)(0x4000 + i), snaData[27 + i]);
|
||||
}
|
||||
|
||||
// 3. Pop the Program Counter off the stack to resume
|
||||
byte pcLow = Memory.Read(Cpu.SP);
|
||||
Cpu.SP++;
|
||||
byte pcHigh = Memory.Read(Cpu.SP);
|
||||
Cpu.SP++;
|
||||
Cpu.PC = (ushort)((pcHigh << 8) | pcLow);
|
||||
}
|
||||
// ====================================================================
|
||||
// SNAPSHOT MANAGEMENT (.SNA)
|
||||
// ====================================================================
|
||||
|
||||
public void SaveSnapshot(string filepath)
|
||||
{
|
||||
// Back up the live state BEFORE modifying the stack
|
||||
ushort originalSP = Cpu.SP;
|
||||
byte originalMemLow = Memory.Read((ushort)(Cpu.SP - 2));
|
||||
byte originalMemHigh = Memory.Read((ushort)(Cpu.SP - 1));
|
||||
|
||||
// Push the PC onto the stack
|
||||
// Push PC for 48K compatibility
|
||||
Cpu.SP -= 2;
|
||||
Memory.Write(Cpu.SP, (byte)(Cpu.PC & 0xFF));
|
||||
Memory.Write((ushort)(Cpu.SP + 1), (byte)(Cpu.PC >> 8));
|
||||
@@ -351,6 +307,7 @@ namespace Core
|
||||
using (System.IO.FileStream fs = new System.IO.FileStream(filepath, System.IO.FileMode.Create))
|
||||
using (System.IO.BinaryWriter bw = new System.IO.BinaryWriter(fs))
|
||||
{
|
||||
// --- 27 BYTE HEADER ---
|
||||
bw.Write(Cpu.I);
|
||||
bw.Write(Cpu.HL_Prime.Low); bw.Write(Cpu.HL_Prime.High);
|
||||
bw.Write(Cpu.DE_Prime.Low); bw.Write(Cpu.DE_Prime.High);
|
||||
@@ -370,9 +327,34 @@ namespace Core
|
||||
bw.Write((byte)Cpu.InterruptMode);
|
||||
bw.Write(IoBus.BorderColourIndex);
|
||||
|
||||
for (int i = 0x4000; i <= 0xFFFF; i++)
|
||||
if (CurrentModel == MachineModel.Spectrum48K)
|
||||
{
|
||||
bw.Write(Memory.Read((ushort)i));
|
||||
// --- 48K FORMAT (49,179 Bytes) ---
|
||||
for (int i = 0x4000; i <= 0xFFFF; i++) bw.Write(Memory.Read((ushort)i));
|
||||
}
|
||||
else
|
||||
{
|
||||
// --- 128K FORMAT (131,103 Bytes) ---
|
||||
int activeBank = Memory.CurrentRamBankSlot3;
|
||||
|
||||
bw.Write(Memory.GetRamBank(5)); // 0x4000 - 0x7FFF
|
||||
bw.Write(Memory.GetRamBank(2)); // 0x8000 - 0xBFFF
|
||||
bw.Write(Memory.GetRamBank(activeBank)); // 0xC000 - 0xFFFF
|
||||
|
||||
// 128K Extensions
|
||||
bw.Write((byte)(Cpu.PC & 0xFF));
|
||||
bw.Write((byte)(Cpu.PC >> 8));
|
||||
bw.Write(Memory.Port7FFD);
|
||||
bw.Write((byte)0); // TR-DOS ROM (0 = unused)
|
||||
|
||||
// Write the remaining 5 unpaged banks
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (i != 5 && i != 2 && i != activeBank)
|
||||
{
|
||||
bw.Write(Memory.GetRamBank(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,5 +363,79 @@ namespace Core
|
||||
Memory.Write((ushort)(originalSP - 2), originalMemLow);
|
||||
Memory.Write((ushort)(originalSP - 1), originalMemHigh);
|
||||
}
|
||||
|
||||
public void LoadSnapshot(byte[] snaData)
|
||||
{
|
||||
bool is128K = snaData.Length == 131103;
|
||||
|
||||
if (snaData.Length != 49179 && !is128K)
|
||||
throw new Exception($"Invalid SNA File Size! Got {snaData.Length} bytes.");
|
||||
|
||||
// Force the machine into the correct mode
|
||||
SetMachineModel(is128K ? MachineModel.SpectrumPlus2A : MachineModel.Spectrum48K);
|
||||
|
||||
// 1. Load Header
|
||||
Cpu.I = snaData[0];
|
||||
Cpu.HL_Prime.Word = (ushort)(snaData[1] | (snaData[2] << 8));
|
||||
Cpu.DE_Prime.Word = (ushort)(snaData[3] | (snaData[4] << 8));
|
||||
Cpu.BC_Prime.Word = (ushort)(snaData[5] | (snaData[6] << 8));
|
||||
Cpu.AF_Prime.Word = (ushort)(snaData[7] | (snaData[8] << 8));
|
||||
|
||||
Cpu.HL.Word = (ushort)(snaData[9] | (snaData[10] << 8));
|
||||
Cpu.DE.Word = (ushort)(snaData[11] | (snaData[12] << 8));
|
||||
Cpu.BC.Word = (ushort)(snaData[13] | (snaData[14] << 8));
|
||||
Cpu.IY.Word = (ushort)(snaData[15] | (snaData[16] << 8));
|
||||
Cpu.IX.Word = (ushort)(snaData[17] | (snaData[18] << 8));
|
||||
|
||||
if ((snaData[19] & 0x04) != 0) { Cpu.ExecuteOpcode(0xFB); /* Fake EI */ }
|
||||
else { Cpu.ExecuteOpcode(0xF3); /* Fake DI */ }
|
||||
|
||||
Cpu.R = snaData[20];
|
||||
Cpu.AF.Word = (ushort)(snaData[21] | (snaData[22] << 8));
|
||||
Cpu.SP = (ushort)(snaData[23] | (snaData[24] << 8));
|
||||
|
||||
if (snaData[25] == 0) Cpu.ExecuteOpcode(0x46); // IM 0
|
||||
else if (snaData[25] == 1) Cpu.ExecuteOpcode(0x56); // IM 1
|
||||
else if (snaData[25] == 2) Cpu.ExecuteOpcode(0x5E); // IM 2
|
||||
|
||||
IoBus.BorderColourIndex = snaData[26];
|
||||
|
||||
// 2. Load RAM
|
||||
if (!is128K)
|
||||
{
|
||||
for (int i = 0; i < 49152; i++) Memory.Write((ushort)(0x4000 + i), snaData[27 + i]);
|
||||
|
||||
byte pcLow = Memory.Read(Cpu.SP); Cpu.SP++;
|
||||
byte pcHigh = Memory.Read(Cpu.SP); Cpu.SP++;
|
||||
Cpu.PC = (ushort)((pcHigh << 8) | pcLow);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cpu.PC = (ushort)(snaData[49179] | (snaData[49180] << 8));
|
||||
byte port7FFD = snaData[49181];
|
||||
|
||||
// THE TOASTRACK FIX: Force Amstrad ROMs into Toastrack compatibility mode!
|
||||
IoBus.WritePort(0x1FFD, 0x04);
|
||||
IoBus.WritePort(0x7FFD, port7FFD);
|
||||
|
||||
int activeBank = port7FFD & 0x07;
|
||||
|
||||
// Load the 3 visible memory chunks
|
||||
Array.Copy(snaData, 27, Memory.GetRamBank(5), 0, 16384);
|
||||
Array.Copy(snaData, 16411, Memory.GetRamBank(2), 0, 16384);
|
||||
Array.Copy(snaData, 32795, Memory.GetRamBank(activeBank), 0, 16384);
|
||||
|
||||
// Load the remaining 5 hidden memory banks
|
||||
int offset = 49183;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
if (i != 5 && i != 2 && i != activeBank)
|
||||
{
|
||||
Array.Copy(snaData, offset, Memory.GetRamBank(i), 0, 16384);
|
||||
offset += 16384;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user