MSXHawk: working savestates

This commit is contained in:
alyosha-tas 2020-01-19 08:39:21 -05:00
parent 5b4b85d2b2
commit 59a22415d2
10 changed files with 184 additions and 90 deletions

View File

@ -63,6 +63,26 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
#endregion
#region State Save / Load
/// <summary>
/// Save State
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="saver">save buffer</param>
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_save_state(IntPtr core, byte[] saver);
/// <summary>
/// Load State
/// </summary>
/// <param name="core">opaque state pointer</param>
/// <param name="loader">load buffer</param>
[DllImport("MSXHAWK.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void MSX_load_state(IntPtr core, byte[] loader);
#endregion
#region Memory Domain Functions
/// <summary>

View File

@ -1,4 +1,5 @@
using System.IO;
using System;
using System.IO;
using BizHawk.Common;
using BizHawk.Emulation.Common;
@ -40,14 +41,6 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
private void SyncState(Serializer ser)
{
byte[] core = null;
if (ser.IsWriter)
{
using var ms = new MemoryStream();
ms.Close();
core = ms.ToArray();
}
ser.BeginSection("MSX");
if (SaveRAM != null)
@ -65,7 +58,15 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
if (ser.IsReader)
{
SyncAllByteArrayDomains();
ser.Sync(nameof(MSX_core), ref MSX_core, false);
LibMSX.MSX_load_state(MSX_Pntr, MSX_core);
Console.WriteLine("here1");
}
else
{
LibMSX.MSX_save_state(MSX_Pntr, MSX_core);
ser.Sync(nameof(MSX_core), ref MSX_core, false);
Console.WriteLine("here2");
}
}
}

View File

@ -60,6 +60,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
}
IntPtr MSX_Pntr { get; set; } = IntPtr.Zero;
byte[] MSX_core = new byte[0x20000];
// Constants
private const int BankSize = 16384;

View File

@ -108,6 +108,26 @@ namespace MSXHawk
return psg.sampleclock;
}
#pragma region State Save / Load
void SaveState(uint8_t* saver)
{
saver = vdp.SaveState(saver);
saver = cpu.SaveState(saver);
saver = psg.SaveState(saver);
saver = MemMap.SaveState(saver);
}
void LoadState(uint8_t* loader)
{
loader = vdp.LoadState(loader);
loader = cpu.LoadState(loader);
loader = psg.LoadState(loader);
loader = MemMap.LoadState(loader);
}
#pragma endregion
#pragma region Memory Domain Functions
uint8_t GetSysBus(uint32_t addr)

View File

@ -48,6 +48,20 @@ MSXHAWK_EXPORT uint32_t MSX_get_audio(MSXCore* p, uint32_t* dest_L, uint32_t* de
return p->GetAudio(dest_L, dest_R, n_samp_L, n_samp_R);
}
#pragma region State Save / Load
// save state
MSXHAWK_EXPORT void MSX_save_state(MSXCore* p, uint8_t* saver)
{
p->SaveState(saver);
}
// load state
MSXHAWK_EXPORT void MSX_load_state(MSXCore* p, uint8_t* loader)
{
p->LoadState(loader);
}
#pragma endregion
#pragma region Memory Domain Functions

View File

@ -155,9 +155,4 @@ namespace MSXHawk
}
}
}
}

View File

@ -14,26 +14,22 @@ namespace MSXHawk
class MemoryManager
{
public:
MemoryManager()
{
};
VDP* vdp_pntr;
SN76489sms* psg_pntr;
Z80A* cpu_pntr;
uint8_t* rom;
// initialized by core loading, not savestated
uint32_t rom_size;
uint32_t rom_mapper;
uint8_t ram[0x2000];
// State
bool PortDEEnabled = false;
bool lagged;
bool start_pressed;
uint8_t controller_byte_1, controller_byte_2;
uint8_t Port01 = 0xFF;
uint8_t Port02 = 0xFF;
uint8_t Port03 = 0x00;
@ -41,11 +37,27 @@ namespace MSXHawk
uint8_t Port05 = 0x00;
uint8_t Port3E = 0xAF;
uint8_t Port3F = 0xFF;
uint8_t PortDE = 0x00;
uint8_t PortDE = 0x00;
uint8_t reg_FFFC, reg_FFFD, reg_FFFE, reg_FFFF;
uint8_t ram[0x2000];
uint8_t cart_ram[0x8000];
uint8_t reg_FFFC, reg_FFFD, reg_FFFE, reg_FFFF;
MemoryManager()
{
};
uint8_t HardwareRead(uint32_t value);
void HardwareWrite(uint32_t addr, uint8_t value);
void remap_ROM_0();
void remap_ROM_1();
void remap_ROM_2();
void remap_RAM();
void Load_ROM(uint8_t* ext_rom, uint32_t ext_rom_size, uint32_t ext_rom_mapper)
{
@ -64,18 +76,6 @@ namespace MSXHawk
remap_RAM();
}
uint8_t HardwareRead(uint32_t value);
void HardwareWrite(uint32_t addr, uint8_t value);
void remap_ROM_0();
void remap_ROM_1();
void remap_ROM_2();
void remap_RAM();
void MemoryWrite(uint32_t addr, uint8_t value)
{
switch (addr)
@ -146,5 +146,68 @@ namespace MSXHawk
return value;
}
#pragma region State Save / Load
uint8_t* SaveState(uint8_t* saver)
{
*saver = (uint8_t)(PortDEEnabled ? 1 : 0); saver++;
*saver = (uint8_t)(lagged ? 1 : 0); saver++;
*saver = (uint8_t)(start_pressed ? 1 : 0); saver++;
*saver = controller_byte_1; saver++;
*saver = controller_byte_2; saver++;
*saver = Port01; saver++;
*saver = Port02; saver++;
*saver = Port03; saver++;
*saver = Port04; saver++;
*saver = Port05; saver++;
*saver = Port3E; saver++;
*saver = Port3F; saver++;
*saver = PortDE; saver++;
*saver = reg_FFFC; saver++;
*saver = reg_FFFD; saver++;
*saver = reg_FFFE; saver++;
*saver = reg_FFFF; saver++;
std::memcpy(saver, &ram, 0x2000); saver += 0x2000;
std::memcpy(saver, &cart_ram, 0x8000); saver += 0x8000;
return saver;
}
uint8_t* LoadState(uint8_t* loader)
{
PortDEEnabled = *loader == 1; loader++;
lagged = *loader == 1; loader++;
start_pressed = *loader == 1; loader++;
controller_byte_1 = *loader; loader++;
controller_byte_2 = *loader; loader++;
Port01 = *loader; loader++;
Port02 = *loader; loader++;
Port03 = *loader; loader++;
Port04 = *loader; loader++;
Port05 = *loader; loader++;
Port3E = *loader; loader++;
Port3F = *loader; loader++;
PortDE = *loader; loader++;
reg_FFFC = *loader; loader++;
reg_FFFD = *loader; loader++;
reg_FFFE = *loader; loader++;
reg_FFFF = *loader; loader++;
std::memcpy(&ram, loader, 0x2000); loader += 0x2000;
std::memcpy(&cart_ram, loader, 0x2000); loader += 0x2000;
remap_ROM_0();
remap_ROM_1();
remap_ROM_2();
remap_RAM();
return loader;
}
#pragma endregion
};
}

View File

@ -239,7 +239,7 @@ namespace MSXHawk
#pragma region State Save / Load
void SaveState(uint8_t* saver)
uint8_t* SaveState(uint8_t* saver)
{
*saver = (uint8_t)(vol_tone ? 1 : 0); saver++;
*saver = (uint8_t)(noise_type ? 1 : 0); saver++;
@ -292,10 +292,12 @@ namespace MSXHawk
*saver = (uint8_t)((old_sample_L >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample_L >> 24) & 0xFF); saver++;
*saver = (uint8_t)(old_sample_R & 0xFF); saver++; *saver = (uint8_t)((old_sample_R >> 8) & 0xFF); saver++;
*saver = (uint8_t)((old_sample_R >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample_R >> 24) & 0xFF); saver++;
*saver = (uint8_t)((old_sample_R >> 16) & 0xFF); saver++; *saver = (uint8_t)((old_sample_R >> 24) & 0xFF); saver++;
return saver;
}
void LoadState(uint8_t* loader)
uint8_t* LoadState(uint8_t* loader)
{
vol_tone = *loader == 1; loader++;
noise_type = *loader == 1; loader++;
@ -349,6 +351,8 @@ namespace MSXHawk
old_sample_R = *loader; loader++; old_sample_R |= (*loader << 8); loader++;
old_sample_R |= (*loader << 16); loader++; old_sample_R |= (*loader << 24); loader++;
return loader;
}
#pragma endregion

View File

@ -1201,7 +1201,7 @@ namespace MSXHawk
#pragma region State Save / Load
void SaveState(uint8_t* saver)
uint8_t* SaveState(uint8_t* saver)
{
*saver = (uint8_t)(VdpWaitingForLatchInt ? 1 : 0); saver++;
*saver = (uint8_t)(VIntPending ? 1 : 0); saver++;
@ -1249,9 +1249,11 @@ namespace MSXHawk
*saver = (uint8_t)(ScanLine & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 8) & 0xFF); saver++;
*saver = (uint8_t)((ScanLine >> 16) & 0xFF); saver++; *saver = (uint8_t)((ScanLine >> 24) & 0xFF); saver++;
return saver;
}
void LoadState(uint8_t* loader)
uint8_t* LoadState(uint8_t* loader)
{
VdpWaitingForLatchInt = *loader == 1; loader++;
VIntPending = *loader == 1; loader++;
@ -1300,11 +1302,11 @@ namespace MSXHawk
ScanLine = *loader; loader++; ScanLine |= (*loader << 8); loader++;
ScanLine |= (*loader << 16); loader++; ScanLine |= (*loader << 24); loader++;
for (uint32_t i = 0; i < 16; i++)
WriteRegister(i, Registers[i]);
for (uint16_t i = 0; i < 0x4000; i++)
UpdatePatternBuffer(i, VRAM[i]);
for (uint32_t i = 0; i < 16; i++) { WriteRegister(i, Registers[i]); }
for (uint16_t i = 0; i < 0x4000; i++) { UpdatePatternBuffer(i, VRAM[i]); }
UpdatePrecomputedPalette();
return loader;
}
#pragma endregion

View File

@ -70,7 +70,7 @@ namespace MSXHawk
uint32_t BUSRQ[19] = {}; // fixed size - do not change at runtime
uint32_t MEMRQ[19] = {}; // fixed size - do not change at runtime
long TotalExecutedCycles;
uint64_t TotalExecutedCycles;
// non-state variables
uint32_t Ztemp1, Ztemp2, Ztemp3, Ztemp4;
@ -962,46 +962,6 @@ namespace MSXHawk
cur_instr[33] = d33; cur_instr[34] = d34; cur_instr[35] = d35;
cur_instr[36] = d36; cur_instr[37] = d37;
}
/*
// State Save/Load
void SyncState(Serializer ser)
{
ser.BeginSection(nameof(Z80A));
ser.Sync(nameof(Regs), ref Regs, false);
ser.Sync("NMI", ref nonMaskableInterrupt);
ser.Sync("NMIPending", ref nonMaskableInterruptPending);
ser.Sync("IM", ref interruptMode);
ser.Sync("IFF1", ref iff1);
ser.Sync("IFF2", ref iff2);
ser.Sync("Halted", ref halted);
ser.Sync(nameof(I_skip), ref I_skip);
ser.Sync("ExecutedCycles", ref TotalExecutedCycles);
ser.Sync(nameof(EI_pending), ref EI_pending);
ser.Sync(nameof(instr_pntr), ref instr_pntr);
ser.Sync(nameof(bus_pntr), ref bus_pntr);
ser.Sync(nameof(mem_pntr), ref mem_pntr);
ser.Sync(nameof(irq_pntr), ref irq_pntr);
ser.Sync(nameof(cur_instr), ref cur_instr, false);
ser.Sync(nameof(BUSRQ), ref BUSRQ, false);
ser.Sync(nameof(IRQS), ref IRQS);
ser.Sync(nameof(MEMRQ), ref MEMRQ, false);
ser.Sync(nameof(opcode), ref opcode);
ser.Sync(nameof(FlagI), ref FlagI);
ser.Sync(nameof(FlagW), ref FlagW);
ser.Sync(nameof(NO_prefix), ref NO_prefix);
ser.Sync(nameof(CB_prefix), ref CB_prefix);
ser.Sync(nameof(IX_prefix), ref IX_prefix);
ser.Sync(nameof(IY_prefix), ref IY_prefix);
ser.Sync(nameof(IXCB_prefix), ref IXCB_prefix);
ser.Sync(nameof(IYCB_prefix), ref IYCB_prefix);
ser.Sync(nameof(EXTD_prefix), ref EXTD_prefix);
ser.Sync(nameof(PRE_SRC), ref PRE_SRC);
ser.EndSection();
}
*/
void InitTableParity()
{
@ -4553,7 +4513,7 @@ namespace MSXHawk
reg_state.append(val_char_1, 4);
reg_state.append(" Cy:");
reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%16u", TotalExecutedCycles));
reg_state.append(val_char_1, sprintf_s(val_char_1, 32, "%16u", (unsigned int)TotalExecutedCycles));
reg_state.append(" ");
reg_state.append(FlagCget() ? "C" : "c");
@ -5168,7 +5128,7 @@ namespace MSXHawk
#pragma region State Save / Load
void SaveState(uint8_t* saver)
uint8_t* SaveState(uint8_t* saver)
{
*saver = (uint8_t)(NO_prefix ? 1 : 0); saver++;
*saver = (uint8_t)(CB_prefix ? 1 : 0); saver++;
@ -5229,9 +5189,16 @@ namespace MSXHawk
*saver = (uint8_t)(MEMRQ[i] & 0xFF); saver++; *saver = (uint8_t)((MEMRQ[i] >> 8) & 0xFF); saver++;
*saver = (uint8_t)((MEMRQ[i] >> 16) & 0xFF); saver++; *saver = (uint8_t)((MEMRQ[i] >> 24) & 0xFF); saver++;
}
*saver = (uint8_t)(TotalExecutedCycles & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 8) & 0xFF); saver++;
*saver = (uint8_t)((TotalExecutedCycles >> 16) & 0xFF); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 24) & 0xFF); saver++;
*saver = (uint8_t)((TotalExecutedCycles >> 16) & 0x32); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 40) & 0xFF); saver++;
*saver = (uint8_t)((TotalExecutedCycles >> 16) & 0x48); saver++; *saver = (uint8_t)((TotalExecutedCycles >> 56) & 0xFF); saver++;
return saver;
}
void LoadState(uint8_t* loader)
uint8_t* LoadState(uint8_t* loader)
{
NO_prefix = *loader == 1; loader++;
CB_prefix = *loader == 1; loader++;
@ -5292,6 +5259,13 @@ namespace MSXHawk
MEMRQ[i] = *loader; loader++; MEMRQ[i] |= (*loader << 8); loader++;
MEMRQ[i] |= (*loader << 16); loader++; MEMRQ[i] |= (*loader << 24); loader++;
}
TotalExecutedCycles = *loader; loader++; TotalExecutedCycles |= (*loader << 8); loader++;
TotalExecutedCycles |= (*loader << 16); loader++; TotalExecutedCycles |= (*loader << 24); loader++;
TotalExecutedCycles |= ((uint64_t)*loader << 32); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 40); loader++;
TotalExecutedCycles |= ((uint64_t)*loader << 48); loader++; TotalExecutedCycles |= ((uint64_t)*loader << 56); loader++;
return loader;
}
#pragma endregion