changeset 1428:2540c05520f2

New savestates are working. New config file option for selecting format states will be saved in. Mostly complete, needs a little more work before release
author Michael Pavone <pavone@retrodev.com>
date Wed, 09 Aug 2017 23:26:51 -0700
parents 4e5797b3935a
children 7e67f8a37051
files blastem.c blastem.h default.cfg genesis.c genesis.h gst.c menu.c serialize.c vdp.c vdp.h
diffstat 10 files changed, 69 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/blastem.c	Sun Aug 06 00:06:36 2017 -0700
+++ b/blastem.c	Wed Aug 09 23:26:51 2017 -0700
@@ -37,6 +37,7 @@
 int exit_after = 0;
 int z80_enabled = 1;
 int frame_limit = 0;
+uint8_t use_native_states = 1;
 
 tern_node * config;
 
@@ -169,8 +170,11 @@
 		free(save_dir);
 		save_dir = get_save_dir(media);
 	}
-	//TODO: make quick save filename dependent on system type
-	parts[2] = "quicksave.gst";
+	if (use_native_states || context->type != SYSTEM_GENESIS) {
+		parts[2] = "quicksave.state";
+	} else {
+		parts[2] = "quicksave.gst";
+	}
 	free(save_state_path);
 	save_state_path = alloc_concat_m(3, parts);
 	context->save_dir = save_dir;
@@ -417,6 +421,12 @@
 	if (!current_system) {
 		fatal_error("Failed to configure emulated machine for %s\n", romfname);
 	}
+	char *state_format = tern_find_path(config, "ui\0state_format\0", TVAL_PTR).ptrval;
+	if (state_format && !strcmp(state_format, "gst")) {
+		use_native_states = 0;
+	} else if (state_format && strcmp(state_format, "native")) {
+		warning("%s is not a valid value for the ui.state_format setting. Valid values are gst and native\n", state_format);
+	}
 	setup_saves(&cart, &info, current_system);
 	update_title(info.name);
 	if (menu) {
--- a/blastem.h	Sun Aug 06 00:06:36 2017 -0700
+++ b/blastem.h	Wed Aug 09 23:26:51 2017 -0700
@@ -14,6 +14,7 @@
 
 extern char *save_state_path;
 extern char *save_filename;
+extern uint8_t use_native_states;
 #define QUICK_SAVE_SLOT 10
 
 #endif //BLASTEM_H_
--- a/default.cfg	Sun Aug 06 00:06:36 2017 -0700
+++ b/default.cfg	Wed Aug 09 23:26:51 2017 -0700
@@ -219,6 +219,8 @@
 	save_path $USERDATA/blastem/$ROMNAME
 	#space delimited list of file extensions to filter against in menu
 	extensions bin gen md smd sms gg
+	#specifies the preferred save-state format, set to gst for Genecyst compatible states
+	state_format native
 }
 
 system {
--- a/genesis.c	Sun Aug 06 00:06:36 2017 -0700
+++ b/genesis.c	Wed Aug 09 23:26:51 2017 -0700
@@ -339,19 +339,23 @@
 			if (slot == QUICK_SAVE_SLOT) {
 				save_path = save_state_path;
 			} else {
-				char slotname[] = "slot_0.gst";
+				char slotname[] = "slot_0.state";
 				slotname[5] = '0' + slot;
+				if (!use_native_states) {
+					strcpy(slotname + 7, "gst");
+				}
 				char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname};
 				save_path = alloc_concat_m(3, parts);
 			}
-			serialize_buffer state;
-			init_serialize(&state);
-			genesis_serialize(gen, &state, address);;
-			FILE *statefile = fopen(save_path, "wb");
-			fwrite(state.data, 1, state.size, statefile);
-			fclose(statefile);
-			free(state.data);
-			//save_gst(gen, save_path, address);
+			if (use_native_states) {
+				serialize_buffer state;
+				init_serialize(&state);
+				genesis_serialize(gen, &state, address);
+				save_to_file(&state, save_path);
+				free(state.data);
+			} else {
+				save_gst(gen, save_path, address);
+			}
 			printf("Saved state to %s\n", save_path);
 			if (slot != QUICK_SAVE_SLOT) {
 				free(save_path);
@@ -1005,26 +1009,19 @@
 	set_keybindings(&gen->io);
 	render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
 	if (statefile) {
-		//first try loading as a GST format savestate
-		uint32_t pc = load_gst(gen, statefile);
-		if (!pc) {
-			//switch to native format if that fails
-			FILE *f = fopen(statefile, "rb");
-			if (!f) {
-				goto state_error;
-			}
-			long statesize = file_size(f);
-			deserialize_buffer state;
-			void *statedata = malloc(statesize);
-			if (statesize != fread(statedata, 1, statesize, f)) {
-				goto state_error;
-			}
-			fclose(f);
-			init_deserialize(&state, statedata, statesize);
+		//first try loading as a native format savestate
+		deserialize_buffer state;
+		uint32_t pc;
+		if (load_from_file(&state, statefile)) {
 			genesis_deserialize(&state, gen);
-			free(statedata);
+			free(state.data);
 			//HACK
 			pc = gen->m68k->last_prefetch_address;
+		} else {
+			pc = load_gst(gen, statefile);
+			if (!pc) {
+				fatal_error("Failed to load save state %s\n", statefile);
+			}
 		}
 		printf("Loaded %s\n", statefile);
 		if (gen->header.enter_debugger) {
@@ -1043,8 +1040,6 @@
 	}
 	handle_reset_requests(gen);
 	return;
-state_error:
-	fatal_error("Failed to load save state %s\n", statefile);
 }
 
 static void resume_genesis(system_header *system)
@@ -1218,7 +1213,7 @@
 		}
 		for (int i = 0; i < CRAM_SIZE; i++)
 		{
-			write_cram(gen->vdp, i, rand());
+			write_cram_internal(gen->vdp, i, rand());
 		}
 		for (int i = 0; i < VSRAM_SIZE; i++)
 		{
--- a/genesis.h	Sun Aug 06 00:06:36 2017 -0700
+++ b/genesis.h	Wed Aug 09 23:26:51 2017 -0700
@@ -61,6 +61,8 @@
 uint16_t read_dma_value(uint32_t address);
 m68k_context * sync_components(m68k_context *context, uint32_t address);
 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t system_opts, uint8_t force_region, rom_info *info_out);
+void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc);
+void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen);
 
 #endif //GENESIS_H_
 
--- a/gst.c	Sun Aug 06 00:06:36 2017 -0700
+++ b/gst.c	Wed Aug 09 23:26:51 2017 -0700
@@ -236,7 +236,7 @@
 	}
 	for (int i = 0; i < CRAM_SIZE; i++) {
 		uint16_t value;
-		write_cram(context, i*2, (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]);
+		write_cram_internal(context, i*2, (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]);
 	}
 	if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) {
 		fputs("Failed to read VSRAM from savestate\n", stderr);
--- a/menu.c	Sun Aug 06 00:06:36 2017 -0700
+++ b/menu.c	Wed Aug 09 23:26:51 2017 -0700
@@ -429,11 +429,20 @@
 					slotname = numslotname;
 				}
 				char const *parts[] = {gen->header.next_context->save_dir, PATH_SEP, slotname};
-				char *gstpath = alloc_concat_m(3, parts);
+				char *statepath = alloc_concat_m(3, parts);
 				genesis_context *next = (genesis_context *)gen->header.next_context;
-				
-				uint32_t pc = load_gst(next, gstpath);
-				free(gstpath);
+				deserialize_buffer state;
+				uint32_t pc = 0;
+				if (load_from_file(&state, statepath)) {
+					genesis_deserialize(&state, next);
+					free(state.data);
+					//HACK
+					pc = next->m68k->last_prefetch_address;
+				} else {
+					strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
+					pc = load_gst(next, statepath);
+				}
+				free(statepath);
 				if (!pc) {
 					break;
 				}
--- a/serialize.c	Sun Aug 06 00:06:36 2017 -0700
+++ b/serialize.c	Wed Aug 09 23:26:51 2017 -0700
@@ -257,7 +257,6 @@
 		fclose(f);
 		return 0;
 	}
-	fclose(f);
 	if (memcmp(ident, sz_ident, sizeof(ident))) {
 		return 0;
 	}
@@ -267,10 +266,12 @@
 	buf->handlers = NULL;
 	buf->max_handler = 8;
 	if (fread(buf->data, 1, buf->size, f) != buf->size) {
+		fclose(f);
 		free(buf->data);
 		buf->data = NULL;
 		buf->size = 0;
 		return 0;
 	}
+	fclose(f);
 	return 1;
 }
--- a/vdp.c	Sun Aug 06 00:06:36 2017 -0700
+++ b/vdp.c	Wed Aug 09 23:26:51 2017 -0700
@@ -774,7 +774,16 @@
 //rough estimate of slot number at which border display starts
 #define BG_START_SLOT 6
 
-void write_cram(vdp_context * context, uint16_t address, uint16_t value)
+void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value)
+{
+	context->cram[addr] = value;
+	context->colors[addr] = color_map[value & CRAM_BITS];
+	context->colors[addr + CRAM_SIZE] = color_map[(value & CRAM_BITS) | FBUF_SHADOW];
+	context->colors[addr + CRAM_SIZE*2] = color_map[(value & CRAM_BITS) | FBUF_HILIGHT];
+	context->colors[addr + CRAM_SIZE*3] = color_map[(value & CRAM_BITS) | FBUF_MODE4];
+}
+
+static void write_cram(vdp_context * context, uint16_t address, uint16_t value)
 {
 	uint16_t addr;
 	if (context->regs[REG_MODE_2] & BIT_MODE_5) {
@@ -783,11 +792,7 @@
 		addr = address & 0x1F;
 		value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00);
 	}
-	context->cram[addr] = value;
-	context->colors[addr] = color_map[value & CRAM_BITS];
-	context->colors[addr + CRAM_SIZE] = color_map[(value & CRAM_BITS) | FBUF_SHADOW];
-	context->colors[addr + CRAM_SIZE*2] = color_map[(value & CRAM_BITS) | FBUF_HILIGHT];
-	context->colors[addr + CRAM_SIZE*3] = color_map[(value & CRAM_BITS) | FBUF_MODE4];
+	write_cram_internal(context, addr, value);
 	
 	if (context->hslot >= BG_START_SLOT && (
 		context->vcounter < context->inactive_start + context->border_bot 
--- a/vdp.h	Sun Aug 06 00:06:36 2017 -0700
+++ b/vdp.h	Wed Aug 09 23:26:51 2017 -0700
@@ -244,7 +244,7 @@
 void vdp_print_reg_explain(vdp_context * context);
 void latch_mode(vdp_context * context);
 uint32_t vdp_cycles_to_frame_end(vdp_context * context);
-void write_cram(vdp_context * context, uint16_t address, uint16_t value);
+void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value);
 void vdp_check_update_sat_byte(vdp_context *context, uint32_t address, uint8_t value);
 void vdp_pbc_pause(vdp_context *context);
 void vdp_release_framebuffer(vdp_context *context);