Save state support

This commit is contained in:
Connor McLaughlin
2019-09-14 20:28:47 +10:00
parent 851ef67814
commit 2560efbebd
16 changed files with 256 additions and 56 deletions

View File

@ -2,6 +2,7 @@
#include "YBaseLib/ByteStream.h"
#include "YBaseLib/Log.h"
#include "YBaseLib/String.h"
#include "common/state_wrapper.h"
#include "cpu_disasm.h"
#include "dma.h"
#include "gpu.h"
@ -29,7 +30,10 @@ void Bus::Reset()
bool Bus::DoState(StateWrapper& sw)
{
return false;
sw.DoBytes(m_ram.data(), m_ram.size());
sw.DoBytes(m_bios.data(), m_bios.size());
sw.Do(&m_tty_line_buffer);
return !sw.HasError();
}
bool Bus::ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value)

View File

@ -39,7 +39,30 @@ void Core::Reset()
bool Core::DoState(StateWrapper& sw)
{
return false;
sw.DoArray(m_regs.r, countof(m_regs.r));
sw.Do(&m_regs.pc);
sw.Do(&m_regs.hi);
sw.Do(&m_regs.lo);
sw.Do(&m_regs.npc);
sw.Do(&m_cop0_regs.BPC);
sw.Do(&m_cop0_regs.BDA);
sw.Do(&m_cop0_regs.JUMPDEST);
sw.Do(&m_cop0_regs.BadVaddr);
sw.Do(&m_cop0_regs.BDAM);
sw.Do(&m_cop0_regs.BPCM);
sw.Do(&m_cop0_regs.EPC);
sw.Do(&m_cop0_regs.PRID);
sw.Do(&m_cop0_regs.sr.bits);
sw.Do(&m_cop0_regs.cause.bits);
sw.Do(&m_cop0_regs.dcic.bits);
sw.Do(&m_next_instruction.bits);
sw.Do(&m_in_branch_delay_slot);
sw.Do(&m_branched);
sw.Do(&m_load_delay_reg);
sw.Do(&m_load_delay_old_value);
sw.Do(&m_cache_control);
sw.DoBytes(m_dcache.data(), m_dcache.size());
return !sw.HasError();
}
void Core::SetPC(u32 new_pc)

View File

@ -1,6 +1,7 @@
#include "dma.h"
#include "YBaseLib/Log.h"
#include "bus.h"
#include "common/state_wrapper.h"
#include "gpu.h"
Log_SetChannel(DMA);
@ -22,6 +23,22 @@ void DMA::Reset()
m_DCIR = 0;
}
bool DMA::DoState(StateWrapper& sw)
{
for (u32 i = 0; i < NUM_CHANNELS; i++)
{
ChannelState& cs = m_state[i];
sw.Do(&cs.base_address);
sw.Do(&cs.block_control.bits);
sw.Do(&cs.channel_control.bits);
sw.Do(&cs.request);
}
sw.Do(&m_DPCR.bits);
sw.Do(&m_DCIR);
return !sw.HasError();
}
u32 DMA::ReadRegister(u32 offset)
{
const u32 channel_index = offset >> 4;

View File

@ -3,6 +3,8 @@
#include "types.h"
#include <array>
class StateWrapper;
class Bus;
class GPU;
@ -30,6 +32,7 @@ public:
bool Initialize(Bus* bus, GPU* gpu);
void Reset();
bool DoState(StateWrapper& sw);
u32 ReadRegister(u32 offset);
void WriteRegister(u32 offset, u32 value);

View File

@ -1,6 +1,7 @@
#include "gpu.h"
#include "YBaseLib/Log.h"
#include "bus.h"
#include "common/state_wrapper.h"
#include "dma.h"
#include "system.h"
Log_SetChannel(GPU);
@ -28,6 +29,46 @@ void GPU::SoftReset()
UpdateGPUSTAT();
}
bool GPU::DoState(StateWrapper& sw)
{
if (sw.IsReading())
FlushRender();
sw.Do(&m_GPUSTAT.bits);
sw.Do(&m_texture_config.base_x);
sw.Do(&m_texture_config.base_y);
sw.Do(&m_texture_config.palette_x);
sw.Do(&m_texture_config.palette_y);
sw.Do(&m_texture_config.page_attribute);
sw.Do(&m_texture_config.palette_attribute);
sw.Do(&m_texture_config.color_mode);
sw.Do(&m_texture_config.page_changed);
sw.Do(&m_texture_config.window_mask_x);
sw.Do(&m_texture_config.window_mask_y);
sw.Do(&m_texture_config.window_offset_x);
sw.Do(&m_texture_config.window_offset_y);
sw.Do(&m_texture_config.x_flip);
sw.Do(&m_texture_config.y_flip);
sw.Do(&m_drawing_area.top_left_x);
sw.Do(&m_drawing_area.top_left_y);
sw.Do(&m_drawing_area.bottom_right_x);
sw.Do(&m_drawing_area.bottom_right_y);
sw.Do(&m_drawing_offset.x);
sw.Do(&m_drawing_offset.y);
sw.Do(&m_drawing_offset.x);
sw.Do(&m_GP0_command);
sw.Do(&m_GPUREAD_buffer);
if (sw.IsReading())
{
m_texture_config.page_changed = true;
UpdateGPUSTAT();
}
return !sw.HasError();
}
void GPU::UpdateGPUSTAT()
{
m_GPUSTAT.ready_to_send_vram = !m_GPUREAD_buffer.empty();
@ -352,7 +393,6 @@ bool GPU::HandleRenderCommand()
ZeroExtend32(words_per_vertex));
DispatchRenderCommand(rc, num_vertices);
UpdateDisplay();
return true;
}
@ -370,7 +410,6 @@ bool GPU::HandleFillRectangleCommand()
Log_DebugPrintf("Fill VRAM rectangle offset=(%u,%u), size=(%u,%u)", dst_x, dst_y, width, height);
FillVRAM(dst_x, dst_y, width, height, color);
UpdateDisplay();
return true;
}
@ -400,7 +439,6 @@ bool GPU::HandleCopyRectangleCPUToVRAMCommand()
FlushRender();
UpdateVRAM(dst_x, dst_y, copy_width, copy_height, &m_GP0_command[3]);
UpdateDisplay();
return true;
}

View File

@ -5,6 +5,8 @@
#include <deque>
#include <vector>
class StateWrapper;
class System;
class Bus;
class DMA;
@ -17,6 +19,7 @@ public:
virtual bool Initialize(System* system, Bus* bus, DMA* dma);
virtual void Reset();
virtual bool DoState(StateWrapper& sw);
u32 ReadRegister(u32 offset);
void WriteRegister(u32 offset, u32 value);
@ -207,11 +210,6 @@ protected:
s32 y;
} m_drawing_offset = {};
struct TexturePageConfig
{
} m_texture_page_config = {};
std::vector<u32> m_GP0_command;
std::deque<u32> m_GPUREAD_buffer;
};

View File

@ -0,0 +1,53 @@
#include "host_interface.h"
#include "YBaseLib/ByteStream.h"
#include "system.h"
HostInterface::HostInterface() = default;
HostInterface::~HostInterface() = default;
bool HostInterface::LoadState(const char* filename)
{
ByteStream* stream;
if (!ByteStream_OpenFileStream(filename, BYTESTREAM_OPEN_READ | BYTESTREAM_OPEN_STREAMED, &stream))
return false;
ReportMessage(SmallString::FromFormat("Loading state from %s...", filename));
const bool result = m_system->LoadState(stream);
if (!result)
{
ReportMessage(SmallString::FromFormat("Loading state from %s failed. Resetting.", filename));
m_system->Reset();
}
stream->Release();
return result;
}
bool HostInterface::SaveState(const char* filename)
{
ByteStream* stream;
if (!ByteStream_OpenFileStream(filename,
BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE | BYTESTREAM_OPEN_TRUNCATE |
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED,
&stream))
{
return false;
}
const bool result = m_system->SaveState(stream);
if (!result)
{
ReportMessage(SmallString::FromFormat("Saving state to %s failed.", filename));
stream->Discard();
}
else
{
ReportMessage(SmallString::FromFormat("State saved to %s.", filename));
stream->Commit();
}
stream->Release();
return result;
}

View File

@ -1,16 +1,29 @@
#pragma once
#include "types.h"
#include <memory>
namespace GL {
class Texture;
}
class System;
class HostInterface
{
public:
HostInterface();
virtual ~HostInterface();
virtual void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) = 0;
virtual void ReportMessage(const char* message) = 0;
// Adds OSD messages, duration is in seconds.
virtual void AddOSDMessage(const char* message, float duration = 2.0f) = 0;
protected:
bool LoadState(const char* filename);
bool SaveState(const char* filename);
std::unique_ptr<System> m_system;
bool m_running = false;
};

View File

@ -42,6 +42,7 @@
<ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="gpu_hw_opengl.cpp" />
<ClCompile Include="host_interface.cpp" />
<ClCompile Include="system.cpp" />
</ItemGroup>
<ItemGroup>

View File

@ -9,6 +9,7 @@
<ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw_opengl.cpp" />
<ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="host_interface.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h" />

View File

@ -1,5 +1,7 @@
#include "system.h"
#include "YBaseLib/ByteStream.h"
#include "bus.h"
#include "common/state_wrapper.h"
#include "cpu_core.h"
#include "dma.h"
#include "gpu.h"
@ -32,6 +34,23 @@ bool System::Initialize()
return true;
}
bool System::DoState(StateWrapper& sw)
{
if (!sw.DoMarker("CPU") || !m_cpu->DoState(sw))
return false;
if (!sw.DoMarker("Bus") || !m_bus->DoState(sw))
return false;
if (!sw.DoMarker("DMA") || !m_dma->DoState(sw))
return false;
if (!sw.DoMarker("GPU") || !m_gpu->DoState(sw))
return false;
return !sw.HasError();
}
void System::Reset()
{
m_cpu->Reset();
@ -41,6 +60,18 @@ void System::Reset()
m_frame_number = 1;
}
bool System::LoadState(ByteStream* state)
{
StateWrapper sw(state, StateWrapper::Mode::Read);
return DoState(sw);
}
bool System::SaveState(ByteStream* state)
{
StateWrapper sw(state, StateWrapper::Mode::Write);
return DoState(sw);
}
void System::RunFrame()
{
u32 current_frame_number = m_frame_number;
@ -134,3 +165,4 @@ bool System::LoadEXE(const char* filename)
return true;
}

View File

@ -1,6 +1,9 @@
#pragma once
#include "types.h"
class ByteStream;
class StateWrapper;
class HostInterface;
namespace CPU
@ -26,11 +29,16 @@ public:
bool Initialize();
void Reset();
bool LoadState(ByteStream* state);
bool SaveState(ByteStream* state);
void RunFrame();
bool LoadEXE(const char* filename);
private:
bool DoState(StateWrapper& sw);
HostInterface* m_host_interface;
std::unique_ptr<CPU::Core> m_cpu;
std::unique_ptr<Bus> m_bus;