# HG changeset patch # User Mike Pavone # Date 1548051598 28800 # Node ID 319d90025d500c410592fdf674a3aea3d943a155 # Parent 7f42a93f18a4a5e00560016233cda2ed85e6d8e0 Implement serialization/deserialization in libretro build diff -r 7f42a93f18a4 -r 319d90025d50 genesis.c --- a/genesis.c Sun Jan 20 19:52:54 2019 -0800 +++ b/genesis.c Sun Jan 20 22:19:58 2019 -0800 @@ -92,6 +92,31 @@ cart_serialize(&gen->header, buf); } +static uint8_t *serialize(system_header *sys, size_t *size_out) +{ + genesis_context *gen = (genesis_context *)sys; + uint32_t address; + if (gen->m68k->resume_pc) { + gen->m68k->target_cycle = gen->m68k->current_cycle; + gen->header.save_state = SERIALIZE_SLOT+1; + resume_68k(gen->m68k); + if (size_out) { + *size_out = gen->serialize_size; + } + return gen->serialize_tmp; + } else { + serialize_buffer state; + init_serialize(&state); + uint32_t address = read_word(4, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k) << 16; + address |= read_word(6, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k); + genesis_serialize(gen, &state, address); + if (size_out) { + *size_out = state.size; + } + return state.data; + } +} + static void ram_deserialize(deserialize_buffer *buf, void *vgen) { genesis_context *gen = vgen; @@ -152,6 +177,19 @@ } update_z80_bank_pointer(gen); adjust_int_cycle(gen->m68k, gen->vdp); + free(buf->handlers); + buf->handlers = NULL; +} + +#include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up +static void deserialize(system_header *sys, uint8_t *data, size_t size) +{ + genesis_context *gen = (genesis_context *)sys; + deserialize_buffer buffer; + init_deserialize(&buffer, data, size); + genesis_deserialize(&buffer, gen); + //HACK: Fix this once PC/IR is represented in a better way in 68K core + gen->m68k->resume_pc = get_native_address_trans(gen->m68k, gen->m68k->last_prefetch_address); } uint16_t read_dma_value(uint32_t address) @@ -382,13 +420,20 @@ sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); } } - char *save_path = get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst"); - if (use_native_states) { + char *save_path = slot == SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst"); + if (use_native_states || slot == SERIALIZE_SLOT) { serialize_buffer state; init_serialize(&state); genesis_serialize(gen, &state, address); - save_to_file(&state, save_path); - free(state.data); + if (slot == SERIALIZE_SLOT) { + gen->serialize_tmp = state.data; + gen->serialize_size = state.size; + context->sync_cycle = context->current_cycle; + context->should_return = 1; + } else { + save_to_file(&state, save_path); + free(state.data); + } } else { save_gst(gen, save_path, address); } @@ -1018,7 +1063,6 @@ gen->master_clock = gen->normal_clock; } -#include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up static uint8_t load_state(system_header *system, uint8_t slot) { genesis_context *gen = (genesis_context *)system; @@ -1297,6 +1341,8 @@ gen->header.keyboard_down = keyboard_down; gen->header.keyboard_up = keyboard_up; gen->header.config_updated = config_updated; + gen->header.serialize = serialize; + gen->header.deserialize = deserialize; gen->header.type = SYSTEM_GENESIS; gen->header.info = *rom; set_region(gen, rom, force_region); diff -r 7f42a93f18a4 -r 319d90025d50 genesis.h --- a/genesis.h Sun Jan 20 19:52:54 2019 -0800 +++ b/genesis.h Sun Jan 20 22:19:58 2019 -0800 @@ -35,6 +35,8 @@ uint8_t *save_storage; void *mapper_temp; eeprom_map *eeprom_map; + uint8_t *serialize_tmp; + size_t serialize_size; uint32_t num_eeprom; uint32_t save_size; uint32_t save_ram_mask; diff -r 7f42a93f18a4 -r 319d90025d50 libblastem.c --- a/libblastem.c Sun Jan 20 19:52:54 2019 -0800 +++ b/libblastem.c Sun Jan 20 22:19:58 2019 -0800 @@ -117,20 +117,34 @@ * returned size is never allowed to be larger than a previous returned * value, to ensure that the frontend can allocate a save state buffer once. */ +static size_t serialize_size_cache; RETRO_API size_t retro_serialize_size(void) { - return 0; + if (!serialize_size_cache) { + uint8_t *tmp = current_system->serialize(current_system, &serialize_size_cache); + free(tmp); + } + return serialize_size_cache; } /* Serializes internal state. If failed, or size is lower than * retro_serialize_size(), it should return false, true otherwise. */ RETRO_API bool retro_serialize(void *data, size_t size) { - return 0; + size_t actual_size; + uint8_t *tmp = current_system->serialize(current_system, &actual_size); + if (actual_size > size) { + free(tmp); + return 0; + } + memcpy(data, tmp, actual_size); + free(tmp); + return 1; } RETRO_API bool retro_unserialize(const void *data, size_t size) { + current_system->deserialize(current_system, (uint8_t *)data, size); return 0; } @@ -145,6 +159,7 @@ /* Loads a game. */ RETRO_API bool retro_load_game(const struct retro_game_info *game) { + serialize_size_cache = 0; if (game->path) { media.dir = path_dirname(game->path); media.name = basename_no_extension(game->path); diff -r 7f42a93f18a4 -r 319d90025d50 saves.h --- a/saves.h Sun Jan 20 19:52:54 2019 -0800 +++ b/saves.h Sun Jan 20 22:19:58 2019 -0800 @@ -6,6 +6,7 @@ #include "system.h" #define QUICK_SAVE_SLOT 10 +#define SERIALIZE_SLOT 11 typedef struct { char *desc; diff -r 7f42a93f18a4 -r 319d90025d50 sms.c --- a/sms.c Sun Jan 20 19:52:54 2019 -0800 +++ b/sms.c Sun Jan 20 22:19:58 2019 -0800 @@ -235,6 +235,18 @@ end_section(buf); } +static uint8_t *serialize(system_header *sys, size_t *size_out) +{ + sms_context *sms = (sms_context *)sys; + serialize_buffer state; + init_serialize(&state); + sms_serialize(sms, &state); + if (size_out) { + *size_out = state.size; + } + return state.data; +} + static void ram_deserialize(deserialize_buffer *buf, void *vsms) { sms_context *sms = vsms; @@ -290,6 +302,16 @@ //cart RAM is enabled, invalidate the region in case there is any code there z80_invalidate_code_range(sms->z80, 0x8000, 0xC000); } + free(buf->handlers); + buf->handlers = NULL; +} + +static void deserialize(system_header *sys, uint8_t *data, size_t size) +{ + sms_context *sms = (sms_context *)sys; + deserialize_buffer buffer; + init_deserialize(&buffer, data, size); + sms_deserialize(&buffer, sms); } static void save_state(sms_context *sms, uint8_t slot) @@ -603,6 +625,8 @@ sms->header.keyboard_down = keyboard_down; sms->header.keyboard_up = keyboard_up; sms->header.config_updated = config_updated; + sms->header.serialize = serialize; + sms->header.deserialize = deserialize; sms->header.type = SYSTEM_SMS; return sms; diff -r 7f42a93f18a4 -r 319d90025d50 system.h --- a/system.h Sun Jan 20 19:52:54 2019 -0800 +++ b/system.h Sun Jan 20 22:19:58 2019 -0800 @@ -1,5 +1,6 @@ #ifndef SYSTEM_H_ #define SYSTEM_H_ +#include #include typedef struct system_header system_header; @@ -27,43 +28,47 @@ typedef void (*system_u8_u8_fun)(system_header *, uint8_t, uint8_t); typedef void (*system_mabs_fun)(system_header *, uint8_t, uint16_t, uint16_t); typedef void (*system_mrel_fun)(system_header *, uint8_t, int32_t, int32_t); +typedef uint8_t *(*system_ptrszt_fun_rptr8)(system_header *, size_t *); +typedef void (*system_ptr8_sizet_fun)(system_header *, uint8_t *, size_t); #include "arena.h" #include "romdb.h" struct system_header { - system_header *next_context; - system_str_fun start_context; - system_fun resume_context; - system_fun load_save; - system_fun persist_save; - system_u8_fun_r8 load_state; - system_fun request_exit; - system_fun soft_reset; - system_fun free_context; - system_fun_r16 get_open_bus_value; - system_u32_fun set_speed_percent; - system_fun inc_debug_mode; - system_u8_u8_fun gamepad_down; - system_u8_u8_fun gamepad_up; - system_u8_u8_fun mouse_down; - system_u8_u8_fun mouse_up; - system_mabs_fun mouse_motion_absolute; - system_mrel_fun mouse_motion_relative; - system_u8_fun keyboard_down; - system_u8_fun keyboard_up; - system_fun config_updated; - rom_info info; - arena *arena; - char *next_rom; - char *save_dir; - uint8_t enter_debugger; - uint8_t should_exit; - uint8_t save_state; - uint8_t delayed_load_slot; - uint8_t has_keyboard; - debugger_type debugger_type; - system_type type; + system_header *next_context; + system_str_fun start_context; + system_fun resume_context; + system_fun load_save; + system_fun persist_save; + system_u8_fun_r8 load_state; + system_fun request_exit; + system_fun soft_reset; + system_fun free_context; + system_fun_r16 get_open_bus_value; + system_u32_fun set_speed_percent; + system_fun inc_debug_mode; + system_u8_u8_fun gamepad_down; + system_u8_u8_fun gamepad_up; + system_u8_u8_fun mouse_down; + system_u8_u8_fun mouse_up; + system_mabs_fun mouse_motion_absolute; + system_mrel_fun mouse_motion_relative; + system_u8_fun keyboard_down; + system_u8_fun keyboard_up; + system_fun config_updated; + system_ptrszt_fun_rptr8 serialize; + system_ptr8_sizet_fun deserialize; + rom_info info; + arena *arena; + char *next_rom; + char *save_dir; + uint8_t enter_debugger; + uint8_t should_exit; + uint8_t save_state; + uint8_t delayed_load_slot; + uint8_t has_keyboard; + debugger_type debugger_type; + system_type type; }; struct system_media {