summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Pavone <pavone@retrodev.com>2019-01-20 22:19:58 -0800
committerMike Pavone <pavone@retrodev.com>2019-01-20 22:19:58 -0800
commitef9e02ca28b67a25c1cd9e203c2e104446b0a5ed (patch)
tree88ff67a34bb3bdbb9ceda54fbdd8ff1592d2c112
parente1c9e57b47c8e374ef7b806c04e412fb6c0b8efa (diff)
Implement serialization/deserialization in libretro build
-rw-r--r--genesis.c56
-rw-r--r--genesis.h2
-rw-r--r--libblastem.c19
-rw-r--r--saves.h1
-rw-r--r--sms.c24
-rw-r--r--system.h69
6 files changed, 132 insertions, 39 deletions
diff --git a/genesis.c b/genesis.c
index e50a87d..8e680e0 100644
--- a/genesis.c
+++ b/genesis.c
@@ -92,6 +92,31 @@ void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68
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 @@ void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen)
}
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 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
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 @@ void set_region(genesis_context *gen, rom_info *info, uint8_t region)
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 @@ genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on
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 --git a/genesis.h b/genesis.h
index 04c9069..d39e800 100644
--- a/genesis.h
+++ b/genesis.h
@@ -35,6 +35,8 @@ struct genesis_context {
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 --git a/libblastem.c b/libblastem.c
index 2312593..8b2ea74 100644
--- a/libblastem.c
+++ b/libblastem.c
@@ -117,20 +117,34 @@ RETRO_API void retro_run(void)
* 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 @@ RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char *code)
/* 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 --git a/saves.h b/saves.h
index 6964e82..8dac45a 100644
--- a/saves.h
+++ b/saves.h
@@ -6,6 +6,7 @@
#include "system.h"
#define QUICK_SAVE_SLOT 10
+#define SERIALIZE_SLOT 11
typedef struct {
char *desc;
diff --git a/sms.c b/sms.c
index 2230466..0ca499c 100644
--- a/sms.c
+++ b/sms.c
@@ -235,6 +235,18 @@ void sms_serialize(sms_context *sms, serialize_buffer *buf)
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 @@ void sms_deserialize(deserialize_buffer *buf, sms_context *sms)
//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_context *alloc_configure_sms(system_media *media, uint32_t opts, uint8_t for
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 --git a/system.h b/system.h
index 0402684..1e574df 100644
--- a/system.h
+++ b/system.h
@@ -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 uint8_t (*system_u8_fun_r8)(system_header *, uint8_t);
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 {