changeset 1690:319d90025d50

Implement serialization/deserialization in libretro build
author Mike Pavone <pavone@retrodev.com>
date Sun, 20 Jan 2019 22:19:58 -0800
parents 7f42a93f18a4
children e96d0d3bec7f
files genesis.c genesis.h libblastem.c saves.h sms.c system.h
diffstat 6 files changed, 132 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- 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);
--- 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;
--- 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);
--- 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;
--- 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;
--- 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 <stddef.h>
 #include <stdint.h>
 
 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 {