From 6121f07c3bf76d1c9f69e1054590e9c8edbeffcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Harsco=C3=ABt?= Date: Mon, 5 Apr 2021 17:07:19 +0200 Subject: [PATCH 1/2] Save state first implem --- lib/cpu.cpp | 22 ++++++++++++++++++++++ lib/cpu.h | 14 ++++++++++++++ lib/emulator.cpp | 14 ++++++++++++++ lib/emulator.h | 11 +++++++++++ lib/gpu.cpp | 16 ++++++++++++++++ lib/gpu.h | 10 ++++++++++ lib/memory.cpp | 23 +++++++++++++++++++++++ lib/memory.h | 10 ++++++++++ src/sdl_display.cpp | 6 ++++++ 9 files changed, 126 insertions(+) diff --git a/lib/cpu.cpp b/lib/cpu.cpp index d8f5341..f64c130 100644 --- a/lib/cpu.cpp +++ b/lib/cpu.cpp @@ -22,6 +22,28 @@ CPU::CPU(Memory* memory) this->memory = memory; } +void CPU::dump_state(cpu_state* state) const +{ + memcpy(state->registers, this->registers, 6*sizeof(uint16_t)); + state->halted = this->halted; + state->divider_cycle_count = this->divider_cycle_count; + state->timer_cycle_count = this->timer_cycle_count; + + state->ime = this->ime; + state->ime_scheduled = this->ime_scheduled; +} + +void CPU::load_state(const cpu_state* const state) +{ + memcpy(this->registers, state->registers, 6 * sizeof(uint16_t)); + this->halted = state->halted ; + this->divider_cycle_count = state->divider_cycle_count ; + this->timer_cycle_count = state->timer_cycle_count ; + + this->ime = state->ime ; + this->ime_scheduled = state->ime_scheduled; +} + void CPU::reset() { memset(registers, 0, 12); diff --git a/lib/cpu.h b/lib/cpu.h index 47f1570..106831f 100644 --- a/lib/cpu.h +++ b/lib/cpu.h @@ -266,6 +266,20 @@ class CPU void init(); uint8_t step(); + struct cpu_state { + uint16_t registers[6]; + uint8_t divider_cycle_count; + uint16_t timer_cycle_count; + + bool ime; + bool ime_scheduled; + + bool halted; + }; + + void dump_state(cpu_state* state) const; + void load_state(const cpu_state* const state); + bool is_double_speed(); }; diff --git a/lib/emulator.cpp b/lib/emulator.cpp index dcec489..bbbb93b 100644 --- a/lib/emulator.cpp +++ b/lib/emulator.cpp @@ -229,6 +229,20 @@ void Emulator::set_rom_file(std::string filename) //reset(); } +void Emulator::save_state() +{ + memory.dump_state(&quick_savestate.mem_state); + cpu.dump_state(&quick_savestate.cpu_state); + gpu.dump_state(&quick_savestate.gpu_state); + +} + +void Emulator::load_state(){ + memory.load_state(&quick_savestate.mem_state); + cpu.load_state(&quick_savestate.cpu_state); + gpu.load_state(&quick_savestate.gpu_state); +} + bool Emulator::is_running() const { return state == emu_state::RUNNING; diff --git a/lib/emulator.h b/lib/emulator.h index dedaf88..febe971 100644 --- a/lib/emulator.h +++ b/lib/emulator.h @@ -47,6 +47,14 @@ class EMULATOR_API Emulator GPU gpu; Sound apu; + struct save_state{ + Memory::memory_state mem_state; + CPU::cpu_state cpu_state; + GPU::gpu_state gpu_state; + }; + + save_state quick_savestate; + uint8_t frame_count; uint8_t serial_byte; @@ -87,6 +95,9 @@ class EMULATOR_API Emulator void set_rom_file(std::string filename); + void save_state(); + void load_state(); + //state functions bool is_running() const; bool is_exiting() const; diff --git a/lib/gpu.cpp b/lib/gpu.cpp index 3cc6fbe..3297d52 100644 --- a/lib/gpu.cpp +++ b/lib/gpu.cpp @@ -54,6 +54,22 @@ PaletteData* const GPU::get_palette_data() return cgb_palettes; } +void GPU::dump_state(gpu_state *state) const +{ + memcpy(state->cgb_palettes, this->cgb_palettes, 2* sizeof(PaletteData)); + memcpy(state->pixels, this->pixels, sizeof(this->pixels)); + memcpy(state->bg_color_prio_line, this->bg_color_prio_line, sizeof(this->bg_color_prio_line)); + state->clock_counter = this->clock_counter; +} + +void GPU::load_state(const gpu_state *const state) +{ + memcpy(this->cgb_palettes, state->cgb_palettes, 2 * sizeof(PaletteData)); + memcpy(this->pixels, state->pixels, sizeof(this->pixels)); + memcpy(this->bg_color_prio_line, state->bg_color_prio_line, sizeof(this->bg_color_prio_line)); + this->clock_counter = state->clock_counter; +} + void GPU::step(uint8_t cycles) { uint8_t stat_val = memory->read_8bits(STAT) | 0x80; diff --git a/lib/gpu.h b/lib/gpu.h index 1c80a95..9120f26 100644 --- a/lib/gpu.h +++ b/lib/gpu.h @@ -54,6 +54,16 @@ class GPU GPU(Memory* memory); ~GPU(); + struct gpu_state{ + PaletteData cgb_palettes[2]; + uint32_t pixels[LCD_HEIGHT][LCD_WIDTH]; + uint16_t clock_counter; + uint8_t bg_color_prio_line[LCD_WIDTH]; + }; + + void dump_state(gpu_state* state) const; + void load_state(const gpu_state* const state); + void step(uint8_t cycles); const uint32_t* get_pixel_data() const; diff --git a/lib/memory.cpp b/lib/memory.cpp index ee3812f..afe9395 100644 --- a/lib/memory.cpp +++ b/lib/memory.cpp @@ -186,6 +186,29 @@ void Memory::load_content(std::istream &file) } } +void Memory::dump_state(memory_state *state) const +{ + memcpy(state->mmap, this->mmap, MEMSIZE); + state->is_cgb = this->is_cgb; + + if(this->is_cgb){ + memcpy(state->vram_banks, this->vram_banks, 2* VRAM_BANK_SIZE); + memcpy(state->wram_banks, this->wram_banks, 7* WRAM_BANK_SIZE); + } +} + +void Memory::load_state(const memory_state *const state) +{ + memcpy(this->mmap, state->mmap, MEMSIZE); + this->is_cgb = state->is_cgb; + + if (this->is_cgb) + { + memcpy(this->vram_banks, state->vram_banks, 2 * VRAM_BANK_SIZE); + memcpy(this->wram_banks, state->wram_banks, 7 * WRAM_BANK_SIZE); + } +} + void Memory::load_content(const uint8_t* data, uint32_t size) { memcpy(mmap, data, size); diff --git a/lib/memory.h b/lib/memory.h index e042e60..ae0cba7 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -66,6 +66,16 @@ class Memory void reset(); + struct memory_state{ + uint8_t mmap[MEMSIZE]; + bool is_cgb; + uint8_t vram_banks[2 * VRAM_BANK_SIZE]; + uint8_t wram_banks[7 * VRAM_BANK_SIZE]; + }; + + void dump_state(memory_state* state) const; + void load_state(const memory_state* const state); + void load_content(std::istream &file); void load_content(const uint8_t* data, uint32_t size); diff --git a/src/sdl_display.cpp b/src/sdl_display.cpp index 9f4f581..a81f2d3 100644 --- a/src/sdl_display.cpp +++ b/src/sdl_display.cpp @@ -197,6 +197,12 @@ bool SDL_Display::handle_events(Emulator &emu) options.debug_ui = !options.debug_ui; options.display_changed = true; break; + case SDL_SCANCODE_F2: + emu.save_state(); + break; + case SDL_SCANCODE_F3: + emu.load_state(); + break; case SDL_SCANCODE_R: emu.reset(); break; From 7f1caceec0899e3704b0d253bde02d0e0f109b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Quentin=20Harsco=C3=ABt?= Date: Mon, 5 Apr 2021 18:05:49 +0200 Subject: [PATCH 2/2] quicksave preview in display --- lib/emulator.h | 14 ++++++++------ src/debug_display.cpp | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/emulator.h b/lib/emulator.h index febe971..b471349 100644 --- a/lib/emulator.h +++ b/lib/emulator.h @@ -29,6 +29,14 @@ class EMULATOR_API Emulator friend class Debug_Display; +public: + struct save_state + { + Memory::memory_state mem_state; + CPU::cpu_state cpu_state; + GPU::gpu_state gpu_state; + }; + private: enum class emu_state : uint8_t { @@ -47,12 +55,6 @@ class EMULATOR_API Emulator GPU gpu; Sound apu; - struct save_state{ - Memory::memory_state mem_state; - CPU::cpu_state cpu_state; - GPU::gpu_state gpu_state; - }; - save_state quick_savestate; uint8_t frame_count; diff --git a/src/debug_display.cpp b/src/debug_display.cpp index 87d14d8..bb33878 100644 --- a/src/debug_display.cpp +++ b/src/debug_display.cpp @@ -54,6 +54,7 @@ static uint16_t sample_offset = 0; static GLuint bg_full; static GLuint bg_tiles[2]; static GLuint screen; +static GLuint quicksave_preview; static MemoryEditor mem_edit; static MemoryEditor mem_edit2; @@ -118,6 +119,7 @@ Debug_Display::Debug_Display(Emulator &emu) bg_tiles[0] = 0; bg_tiles[1]= 0; screen = 0; + quicksave_preview = 0; hqxInit(); } @@ -598,6 +600,25 @@ void Debug_Display::update(const uint32_t *pixels) ImGui::TreePop(); } + if(ImGui::TreeNode("Quick Save")){ + if(ImGui::Button("Save")) + { + emu.save_state(); + } + ImGui::SameLine(); + if(ImGui::Button("Restore")) + { + emu.load_state(); + } + + LoadTextureFromPixels((const uint32_t*)&emu.quick_savestate.gpu_state.pixels[0], &quicksave_preview, LCD_WIDTH, LCD_HEIGHT); + float ratio = (ImGui::GetWindowWidth() * 0.8f)/LCD_WIDTH; + ImGui::Image((void *)(intptr_t)quicksave_preview, ImVec2(LCD_WIDTH * ratio, LCD_HEIGHT * ratio)); + + ImGui::TreePop(); + } + + ImGui::End(); }