diff --git a/Core/debugger.c b/Core/debugger.c index 73bd80a..64fc9ee 100644 --- a/Core/debugger.c +++ b/Core/debugger.c @@ -1899,7 +1899,7 @@ static bool undo(GB_gameboy_t *gb, char *arguments, char *modifiers, const debug return true; } uint16_t pc = gb->pc; - GB_load_state_from_buffer(gb, gb->undo_state, GB_get_save_state_size(gb)); + GB_load_state_from_buffer(gb, gb->undo_state, GB_get_save_state_size_no_bess(gb)); GB_log(gb, "Reverted a \"%s\" command.\n", gb->undo_label); if (pc != gb->pc) { GB_cpu_disassemble(gb, gb->pc, 5); @@ -2205,8 +2205,8 @@ bool GB_debugger_execute_command(GB_gameboy_t *gb, char *input) const debugger_command_t *command = find_command(command_string); if (command) { - uint8_t *old_state = malloc(GB_get_save_state_size(gb)); - GB_save_state_to_buffer(gb, old_state); + uint8_t *old_state = malloc(GB_get_save_state_size_no_bess(gb)); + GB_save_state_to_buffer_no_bess(gb, old_state); bool ret = command->implementation(gb, arguments, modifiers, command); if (!ret) { // Command continues, save state in any case free(gb->undo_state); @@ -2214,9 +2214,9 @@ bool GB_debugger_execute_command(GB_gameboy_t *gb, char *input) gb->undo_label = command->command; } else { - uint8_t *new_state = malloc(GB_get_save_state_size(gb)); - GB_save_state_to_buffer(gb, new_state); - if (memcmp(new_state, old_state, GB_get_save_state_size(gb)) != 0) { + uint8_t *new_state = malloc(GB_get_save_state_size_no_bess(gb)); + GB_save_state_to_buffer_no_bess(gb, new_state); + if (memcmp(new_state, old_state, GB_get_save_state_size_no_bess(gb)) != 0) { // State changed, save the old state as the new undo state free(gb->undo_state); gb->undo_state = old_state; @@ -2306,8 +2306,8 @@ void GB_debugger_run(GB_gameboy_t *gb) if (gb->debug_disable) return; if (!gb->undo_state) { - gb->undo_state = malloc(GB_get_save_state_size(gb)); - GB_save_state_to_buffer(gb, gb->undo_state); + gb->undo_state = malloc(GB_get_save_state_size_no_bess(gb)); + GB_save_state_to_buffer_no_bess(gb, gb->undo_state); } char *input = NULL; @@ -2355,9 +2355,9 @@ next_command: } else if (jump_to_result == JUMP_TO_NONTRIVIAL) { if (!gb->nontrivial_jump_state) { - gb->nontrivial_jump_state = malloc(GB_get_save_state_size(gb)); + gb->nontrivial_jump_state = malloc(GB_get_save_state_size_no_bess(gb)); } - GB_save_state_to_buffer(gb, gb->nontrivial_jump_state); + GB_save_state_to_buffer_no_bess(gb, gb->nontrivial_jump_state); gb->non_trivial_jump_breakpoint_occured = false; should_delete_state = false; } diff --git a/Core/rewind.c b/Core/rewind.c index c3900d6..d305528 100644 --- a/Core/rewind.c +++ b/Core/rewind.c @@ -108,7 +108,7 @@ static void state_decompress(const uint8_t *prev, uint8_t *data, uint8_t *dest, void GB_rewind_push(GB_gameboy_t *gb) { - const size_t save_size = GB_get_save_state_size(gb); + const size_t save_size = GB_get_save_state_size_no_bess(gb); if (!gb->rewind_sequences) { if (gb->rewind_buffer_length) { gb->rewind_sequences = malloc(sizeof(*gb->rewind_sequences) * gb->rewind_buffer_length); @@ -140,11 +140,11 @@ void GB_rewind_push(GB_gameboy_t *gb) if (!gb->rewind_sequences[gb->rewind_pos].key_state) { gb->rewind_sequences[gb->rewind_pos].key_state = malloc(save_size); - GB_save_state_to_buffer(gb, gb->rewind_sequences[gb->rewind_pos].key_state); + GB_save_state_to_buffer_no_bess(gb, gb->rewind_sequences[gb->rewind_pos].key_state); } else { uint8_t *save_state = malloc(save_size); - GB_save_state_to_buffer(gb, save_state); + GB_save_state_to_buffer_no_bess(gb, save_state); gb->rewind_sequences[gb->rewind_pos].compressed_states[gb->rewind_sequences[gb->rewind_pos].pos++] = state_compress(gb->rewind_sequences[gb->rewind_pos].key_state, save_state, save_size); free(save_state); @@ -158,7 +158,7 @@ bool GB_rewind_pop(GB_gameboy_t *gb) return false; } - const size_t save_size = GB_get_save_state_size(gb); + const size_t save_size = GB_get_save_state_size_no_bess(gb); if (gb->rewind_sequences[gb->rewind_pos].pos == 0) { GB_load_state_from_buffer(gb, gb->rewind_sequences[gb->rewind_pos].key_state, save_size); free(gb->rewind_sequences[gb->rewind_pos].key_state); diff --git a/Core/save_state.c b/Core/save_state.c index f279b61..6aa4f37 100644 --- a/Core/save_state.c +++ b/Core/save_state.c @@ -218,7 +218,7 @@ static size_t bess_size_for_cartridge(const GB_cartridge_t *cart) } } -size_t GB_get_save_state_size(GB_gameboy_t *gb) +size_t GB_get_save_state_size_no_bess(GB_gameboy_t *gb) { return GB_SECTION_SIZE(header) + GB_SECTION_SIZE(core_state) + sizeof(uint32_t) @@ -232,7 +232,12 @@ size_t GB_get_save_state_size(GB_gameboy_t *gb) + (GB_is_hle_sgb(gb)? sizeof(*gb->sgb) + sizeof(uint32_t) : 0) + gb->mbc_ram_size + gb->ram_size - + gb->vram_size + + gb->vram_size; +} + +size_t GB_get_save_state_size(GB_gameboy_t *gb) +{ + return GB_get_save_state_size_no_bess(gb) + // BESS + sizeof(BESS_CORE_t) + sizeof(BESS_block_t) // NAME @@ -453,7 +458,7 @@ static int save_bess_mbc_block(GB_gameboy_t *gb, virtual_file_t *file) return 0; } -static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file) +static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file, bool append_bess) { if (file->write(file, GB_GET_SECTION(gb, header), GB_SECTION_SIZE(header)) != GB_SECTION_SIZE(header)) goto error; if (!DUMP_SECTION(gb, file, core_state)) goto error; @@ -475,6 +480,7 @@ static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file) if (!dump_section(file, gb->sgb, sizeof(*gb->sgb))) goto error; } + BESS_CORE_t bess_core = {0,}; bess_core.mbc_ram.offset = LE32(file->tell(file)); @@ -495,6 +501,8 @@ static int save_state_internal(GB_gameboy_t *gb, virtual_file_t *file) goto error; } + if (!append_bess) return 0; + BESS_footer_t bess_footer = { .start_offset = LE32(file->tell(file)), .magic = BE32('BESS'), @@ -694,7 +702,7 @@ int GB_save_state(GB_gameboy_t *gb, const char *path) .tell = file_tell, .file = f, }; - int ret = save_state_internal(gb, &file); + int ret = save_state_internal(gb, &file, true); fclose(f); return ret; } @@ -709,10 +717,23 @@ void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer) .position = 0, }; - save_state_internal(gb, &file); + save_state_internal(gb, &file, true); assert(file.position == GB_get_save_state_size(gb)); } +void GB_save_state_to_buffer_no_bess(GB_gameboy_t *gb, uint8_t *buffer) +{ + virtual_file_t file = { + .write = buffer_write, + .seek = buffer_seek, + .tell = buffer_tell, + .buffer = (uint8_t *)buffer, + .position = 0, + }; + + save_state_internal(gb, &file, false); + assert(file.position == GB_get_save_state_size_no_bess(gb)); +} static bool read_section(virtual_file_t *file, void *dest, uint32_t size, bool fix_broken_windows_saves) { diff --git a/Core/save_state.h b/Core/save_state.h index 8e5fc4e..0c447d9 100644 --- a/Core/save_state.h +++ b/Core/save_state.h @@ -27,4 +27,11 @@ void GB_save_state_to_buffer(GB_gameboy_t *gb, uint8_t *buffer); int GB_load_state(GB_gameboy_t *gb, const char *path); int GB_load_state_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t length); + +#ifdef GB_INTERNAL +/* For internal in-memory save states (rewind, debugger) that do not need BESS */ +size_t GB_get_save_state_size_no_bess(GB_gameboy_t *gb); +void GB_save_state_to_buffer_no_bess(GB_gameboy_t *gb, uint8_t *buffer); +#endif + #endif /* save_state_h */