mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-25 23:25:41 +00:00
Save state support
This commit is contained in:
parent
851ef67814
commit
2560efbebd
|
@ -2,6 +2,7 @@
|
||||||
#include "YBaseLib/ByteStream.h"
|
#include "YBaseLib/ByteStream.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <deque>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -111,6 +112,28 @@ public:
|
||||||
DoArray(data->data(), data->size());
|
DoArray(data->data(), data->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Do(std::deque<T>* data)
|
||||||
|
{
|
||||||
|
u32 length = static_cast<u32>(data->size());
|
||||||
|
Do(&length);
|
||||||
|
if (m_mode == Mode::Read)
|
||||||
|
{
|
||||||
|
data->clear();
|
||||||
|
for (u32 i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
T value;
|
||||||
|
Do(&value);
|
||||||
|
data->push_back(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < length; i++)
|
||||||
|
Do(&data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DoMarker(const char* marker);
|
bool DoMarker(const char* marker);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#include "YBaseLib/Assert.h"
|
#include "YBaseLib/Assert.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "YBaseLib/StringConverter.h"
|
#include "YBaseLib/StringConverter.h"
|
||||||
#include "sdl_interface.h"
|
|
||||||
#include "pse/types.h"
|
|
||||||
#include "pse/system.h"
|
#include "pse/system.h"
|
||||||
|
#include "pse/types.h"
|
||||||
|
#include "sdl_interface.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
@ -24,14 +24,6 @@ static int NoGUITest()
|
||||||
|
|
||||||
static int Run(int argc, char* argv[])
|
static int Run(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
#if 0
|
|
||||||
if (argc < 2)
|
|
||||||
{
|
|
||||||
std::fprintf(stderr, "Usage: %s <path to system ini> [save state index]\n", argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// init sdl
|
// init sdl
|
||||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0)
|
||||||
{
|
{
|
||||||
|
@ -48,11 +40,25 @@ static int Run(int argc, char* argv[])
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// create system
|
// parameters
|
||||||
|
const char* filename = nullptr;
|
||||||
s32 state_index = -1;
|
s32 state_index = -1;
|
||||||
if (argc > 2)
|
for (int i = 1; i < argc; i++)
|
||||||
state_index = StringConverter::StringToInt32(argv[2]);
|
{
|
||||||
if (!host_interface->InitializeSystem("", state_index))
|
#define CHECK_ARG(str) !std::strcmp(argv[i], str)
|
||||||
|
#define CHECK_ARG_PARAM(str) (!std::strcmp(argv[i], str) && ((i + 1) < argc))
|
||||||
|
|
||||||
|
if (CHECK_ARG_PARAM("-state"))
|
||||||
|
state_index = std::atoi(argv[++i]);
|
||||||
|
else
|
||||||
|
filename = argv[i];
|
||||||
|
|
||||||
|
#undef CHECK_ARG
|
||||||
|
#undef CHECK_ARG_PARAM
|
||||||
|
}
|
||||||
|
|
||||||
|
// create system
|
||||||
|
if (!host_interface->InitializeSystem(filename, state_index))
|
||||||
{
|
{
|
||||||
host_interface.reset();
|
host_interface.reset();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
@ -83,6 +89,6 @@ int main(int argc, char* argv[])
|
||||||
g_pLog->SetFilterLevel(LOGLEVEL_DEBUG);
|
g_pLog->SetFilterLevel(LOGLEVEL_DEBUG);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//return NoGUITest();
|
// return NoGUITest();
|
||||||
return Run(argc, argv);
|
return Run(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,15 +148,13 @@ std::unique_ptr<SDLInterface> SDLInterface::Create()
|
||||||
return intf;
|
return intf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TinyString SDLInterface::GetSaveStateFilename(u32 index)
|
TinyString SDLInterface::GetSaveStateFilename(u32 index)
|
||||||
// {
|
{
|
||||||
// return TinyString::FromFormat("savestate_%u.bin", index);
|
return TinyString::FromFormat("savestate_%u.bin", index);
|
||||||
// }
|
}
|
||||||
|
|
||||||
bool SDLInterface::InitializeSystem(const char* filename, s32 save_state_index /* = -1 */)
|
bool SDLInterface::InitializeSystem(const char* filename, s32 save_state_index /* = -1 */)
|
||||||
{
|
{
|
||||||
Error error;
|
|
||||||
|
|
||||||
m_system = std::make_unique<System>(this);
|
m_system = std::make_unique<System>(this);
|
||||||
if (!m_system->Initialize())
|
if (!m_system->Initialize())
|
||||||
{
|
{
|
||||||
|
@ -164,21 +162,13 @@ bool SDLInterface::InitializeSystem(const char* filename, s32 save_state_index /
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
m_system->Reset();
|
||||||
|
|
||||||
if (save_state_index >= 0)
|
if (save_state_index >= 0)
|
||||||
{
|
{
|
||||||
// Load the save state.
|
// Load the save state.
|
||||||
if (!HostInterface::LoadSystemState(GetSaveStateFilename(static_cast<u32>(save_state_index)), &error))
|
LoadState(GetSaveStateFilename(static_cast<u32>(save_state_index)));
|
||||||
{
|
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Loading save state failed", error.GetErrorCodeAndDescription(),
|
|
||||||
m_window);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_system->Reset();
|
|
||||||
|
|
||||||
//m_system->LoadEXE("tests/psxtest_cpu.psxexe");
|
|
||||||
|
|
||||||
// Resume execution.
|
// Resume execution.
|
||||||
m_running = true;
|
m_running = true;
|
||||||
|
@ -458,21 +448,12 @@ void SDLInterface::RenderOSDMessages()
|
||||||
|
|
||||||
void SDLInterface::DoLoadState(u32 index)
|
void SDLInterface::DoLoadState(u32 index)
|
||||||
{
|
{
|
||||||
#if 0
|
LoadState(GetSaveStateFilename(index));
|
||||||
Error error;
|
|
||||||
if (!LoadSystemState(TinyString::FromFormat("savestate_%u.bin", index), &error))
|
|
||||||
{
|
|
||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Loading save state failed", error.GetErrorCodeAndDescription(),
|
|
||||||
m_window);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLInterface::DoSaveState(u32 index)
|
void SDLInterface::DoSaveState(u32 index)
|
||||||
{
|
{
|
||||||
#if 0
|
SaveState(GetSaveStateFilename(index));
|
||||||
SaveSystemState(TinyString::FromFormat("savestate_%u.bin", index));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SDLInterface::Run()
|
void SDLInterface::Run()
|
||||||
|
|
|
@ -19,6 +19,8 @@ public:
|
||||||
|
|
||||||
static std::unique_ptr<SDLInterface> Create();
|
static std::unique_ptr<SDLInterface> Create();
|
||||||
|
|
||||||
|
static TinyString GetSaveStateFilename(u32 index);
|
||||||
|
|
||||||
void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) override;
|
void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) override;
|
||||||
|
|
||||||
void ReportMessage(const char* message) override;
|
void ReportMessage(const char* message) override;
|
||||||
|
@ -61,7 +63,6 @@ private:
|
||||||
int m_window_width = 0;
|
int m_window_width = 0;
|
||||||
int m_window_height = 0;
|
int m_window_height = 0;
|
||||||
|
|
||||||
std::unique_ptr<System> m_system;
|
|
||||||
GL::Program m_display_program;
|
GL::Program m_display_program;
|
||||||
GLuint m_display_vao = 0;
|
GLuint m_display_vao = 0;
|
||||||
GL::Texture* m_display_texture = nullptr;
|
GL::Texture* m_display_texture = nullptr;
|
||||||
|
@ -73,6 +74,4 @@ private:
|
||||||
|
|
||||||
std::deque<OSDMessage> m_osd_messages;
|
std::deque<OSDMessage> m_osd_messages;
|
||||||
std::mutex m_osd_messages_lock;
|
std::mutex m_osd_messages_lock;
|
||||||
|
|
||||||
bool m_running = false;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "YBaseLib/ByteStream.h"
|
#include "YBaseLib/ByteStream.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "YBaseLib/String.h"
|
#include "YBaseLib/String.h"
|
||||||
|
#include "common/state_wrapper.h"
|
||||||
#include "cpu_disasm.h"
|
#include "cpu_disasm.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
|
@ -29,7 +30,10 @@ void Bus::Reset()
|
||||||
|
|
||||||
bool Bus::DoState(StateWrapper& sw)
|
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)
|
bool Bus::ReadByte(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u8* value)
|
||||||
|
|
|
@ -39,7 +39,30 @@ void Core::Reset()
|
||||||
|
|
||||||
bool Core::DoState(StateWrapper& sw)
|
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)
|
void Core::SetPC(u32 new_pc)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
|
#include "common/state_wrapper.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
Log_SetChannel(DMA);
|
Log_SetChannel(DMA);
|
||||||
|
|
||||||
|
@ -22,6 +23,22 @@ void DMA::Reset()
|
||||||
m_DCIR = 0;
|
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)
|
u32 DMA::ReadRegister(u32 offset)
|
||||||
{
|
{
|
||||||
const u32 channel_index = offset >> 4;
|
const u32 channel_index = offset >> 4;
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
class StateWrapper;
|
||||||
|
|
||||||
class Bus;
|
class Bus;
|
||||||
class GPU;
|
class GPU;
|
||||||
|
|
||||||
|
@ -30,6 +32,7 @@ public:
|
||||||
|
|
||||||
bool Initialize(Bus* bus, GPU* gpu);
|
bool Initialize(Bus* bus, GPU* gpu);
|
||||||
void Reset();
|
void Reset();
|
||||||
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
u32 ReadRegister(u32 offset);
|
u32 ReadRegister(u32 offset);
|
||||||
void WriteRegister(u32 offset, u32 value);
|
void WriteRegister(u32 offset, u32 value);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
#include "YBaseLib/Log.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
|
#include "common/state_wrapper.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
Log_SetChannel(GPU);
|
Log_SetChannel(GPU);
|
||||||
|
@ -28,6 +29,46 @@ void GPU::SoftReset()
|
||||||
UpdateGPUSTAT();
|
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()
|
void GPU::UpdateGPUSTAT()
|
||||||
{
|
{
|
||||||
m_GPUSTAT.ready_to_send_vram = !m_GPUREAD_buffer.empty();
|
m_GPUSTAT.ready_to_send_vram = !m_GPUREAD_buffer.empty();
|
||||||
|
@ -352,7 +393,6 @@ bool GPU::HandleRenderCommand()
|
||||||
ZeroExtend32(words_per_vertex));
|
ZeroExtend32(words_per_vertex));
|
||||||
|
|
||||||
DispatchRenderCommand(rc, num_vertices);
|
DispatchRenderCommand(rc, num_vertices);
|
||||||
UpdateDisplay();
|
|
||||||
return true;
|
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);
|
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);
|
FillVRAM(dst_x, dst_y, width, height, color);
|
||||||
UpdateDisplay();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -400,7 +439,6 @@ bool GPU::HandleCopyRectangleCPUToVRAMCommand()
|
||||||
|
|
||||||
FlushRender();
|
FlushRender();
|
||||||
UpdateVRAM(dst_x, dst_y, copy_width, copy_height, &m_GP0_command[3]);
|
UpdateVRAM(dst_x, dst_y, copy_width, copy_height, &m_GP0_command[3]);
|
||||||
UpdateDisplay();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
class StateWrapper;
|
||||||
|
|
||||||
class System;
|
class System;
|
||||||
class Bus;
|
class Bus;
|
||||||
class DMA;
|
class DMA;
|
||||||
|
@ -17,6 +19,7 @@ public:
|
||||||
|
|
||||||
virtual bool Initialize(System* system, Bus* bus, DMA* dma);
|
virtual bool Initialize(System* system, Bus* bus, DMA* dma);
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
|
virtual bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
u32 ReadRegister(u32 offset);
|
u32 ReadRegister(u32 offset);
|
||||||
void WriteRegister(u32 offset, u32 value);
|
void WriteRegister(u32 offset, u32 value);
|
||||||
|
@ -207,11 +210,6 @@ protected:
|
||||||
s32 y;
|
s32 y;
|
||||||
} m_drawing_offset = {};
|
} m_drawing_offset = {};
|
||||||
|
|
||||||
struct TexturePageConfig
|
|
||||||
{
|
|
||||||
|
|
||||||
} m_texture_page_config = {};
|
|
||||||
|
|
||||||
std::vector<u32> m_GP0_command;
|
std::vector<u32> m_GP0_command;
|
||||||
std::deque<u32> m_GPUREAD_buffer;
|
std::deque<u32> m_GPUREAD_buffer;
|
||||||
};
|
};
|
||||||
|
|
53
src/pse/host_interface.cpp
Normal file
53
src/pse/host_interface.cpp
Normal 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;
|
||||||
|
}
|
|
@ -1,16 +1,29 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace GL {
|
namespace GL {
|
||||||
class Texture;
|
class Texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class System;
|
||||||
|
|
||||||
class HostInterface
|
class HostInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
HostInterface();
|
||||||
|
virtual ~HostInterface();
|
||||||
|
|
||||||
virtual void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) = 0;
|
virtual void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) = 0;
|
||||||
virtual void ReportMessage(const char* message) = 0;
|
virtual void ReportMessage(const char* message) = 0;
|
||||||
|
|
||||||
// Adds OSD messages, duration is in seconds.
|
// Adds OSD messages, duration is in seconds.
|
||||||
virtual void AddOSDMessage(const char* message, float duration = 2.0f) = 0;
|
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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
<ClCompile Include="gpu.cpp" />
|
<ClCompile Include="gpu.cpp" />
|
||||||
<ClCompile Include="gpu_hw.cpp" />
|
<ClCompile Include="gpu_hw.cpp" />
|
||||||
<ClCompile Include="gpu_hw_opengl.cpp" />
|
<ClCompile Include="gpu_hw_opengl.cpp" />
|
||||||
|
<ClCompile Include="host_interface.cpp" />
|
||||||
<ClCompile Include="system.cpp" />
|
<ClCompile Include="system.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
<ClCompile Include="gpu.cpp" />
|
<ClCompile Include="gpu.cpp" />
|
||||||
<ClCompile Include="gpu_hw_opengl.cpp" />
|
<ClCompile Include="gpu_hw_opengl.cpp" />
|
||||||
<ClCompile Include="gpu_hw.cpp" />
|
<ClCompile Include="gpu_hw.cpp" />
|
||||||
|
<ClCompile Include="host_interface.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="types.h" />
|
<ClInclude Include="types.h" />
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include "YBaseLib/ByteStream.h"
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
|
#include "common/state_wrapper.h"
|
||||||
#include "cpu_core.h"
|
#include "cpu_core.h"
|
||||||
#include "dma.h"
|
#include "dma.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
|
@ -32,6 +34,23 @@ bool System::Initialize()
|
||||||
return true;
|
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()
|
void System::Reset()
|
||||||
{
|
{
|
||||||
m_cpu->Reset();
|
m_cpu->Reset();
|
||||||
|
@ -41,6 +60,18 @@ void System::Reset()
|
||||||
m_frame_number = 1;
|
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()
|
void System::RunFrame()
|
||||||
{
|
{
|
||||||
u32 current_frame_number = m_frame_number;
|
u32 current_frame_number = m_frame_number;
|
||||||
|
@ -134,3 +165,4 @@ bool System::LoadEXE(const char* filename)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
class ByteStream;
|
||||||
|
class StateWrapper;
|
||||||
|
|
||||||
class HostInterface;
|
class HostInterface;
|
||||||
|
|
||||||
namespace CPU
|
namespace CPU
|
||||||
|
@ -26,11 +29,16 @@ public:
|
||||||
bool Initialize();
|
bool Initialize();
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
bool LoadState(ByteStream* state);
|
||||||
|
bool SaveState(ByteStream* state);
|
||||||
|
|
||||||
void RunFrame();
|
void RunFrame();
|
||||||
|
|
||||||
bool LoadEXE(const char* filename);
|
bool LoadEXE(const char* filename);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool DoState(StateWrapper& sw);
|
||||||
|
|
||||||
HostInterface* m_host_interface;
|
HostInterface* m_host_interface;
|
||||||
std::unique_ptr<CPU::Core> m_cpu;
|
std::unique_ptr<CPU::Core> m_cpu;
|
||||||
std::unique_ptr<Bus> m_bus;
|
std::unique_ptr<Bus> m_bus;
|
||||||
|
|
Loading…
Reference in a new issue