summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2017-08-09 23:26:51 -0700
committerMichael Pavone <pavone@retrodev.com>2017-08-09 23:26:51 -0700
commit5b2b37e775d719fc055ef5e8e59cf965a8049e11 (patch)
tree4662dab8115571aaced5ee6e2d1c80cc7839f3be
parent581601741c3b94bc66a03eece1774618312b260a (diff)
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
-rw-r--r--blastem.c14
-rw-r--r--blastem.h1
-rw-r--r--default.cfg2
-rw-r--r--genesis.c53
-rw-r--r--genesis.h2
-rw-r--r--gst.c2
-rw-r--r--menu.c17
-rw-r--r--serialize.c3
-rw-r--r--vdp.c17
-rw-r--r--vdp.h2
10 files changed, 69 insertions, 44 deletions
diff --git a/blastem.c b/blastem.c
index 9a1b01c..1ab6e8b 100644
--- a/blastem.c
+++ b/blastem.c
@@ -37,6 +37,7 @@ int headless = 0;
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 @@ void setup_saves(system_media *media, rom_info *info, system_header *context)
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 @@ int main(int argc, char ** argv)
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) {
diff --git a/blastem.h b/blastem.h
index 790b10e..c06e002 100644
--- a/blastem.h
+++ b/blastem.h
@@ -14,6 +14,7 @@ extern system_header *current_system;
extern char *save_state_path;
extern char *save_filename;
+extern uint8_t use_native_states;
#define QUICK_SAVE_SLOT 10
#endif //BLASTEM_H_
diff --git a/default.cfg b/default.cfg
index c91425b..27ab8fc 100644
--- a/default.cfg
+++ b/default.cfg
@@ -219,6 +219,8 @@ ui {
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 {
diff --git a/genesis.c b/genesis.c
index 7e3c145..c35d459 100644
--- a/genesis.c
+++ b/genesis.c
@@ -339,19 +339,23 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
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 @@ static void start_genesis(system_header *system, char *statefile)
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 @@ static void start_genesis(system_header *system, char *statefile)
}
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 @@ genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on
}
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++)
{
diff --git a/genesis.h b/genesis.h
index 538f7f3..6229a8e 100644
--- a/genesis.h
+++ b/genesis.h
@@ -61,6 +61,8 @@ struct genesis_context {
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_
diff --git a/gst.c b/gst.c
index 6737eee..c74dab2 100644
--- a/gst.c
+++ b/gst.c
@@ -236,7 +236,7 @@ uint8_t vdp_load_gst(vdp_context * context, FILE * state_file)
}
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);
diff --git a/menu.c b/menu.c
index 751d8f3..c8ccc43 100644
--- a/menu.c
+++ b/menu.c
@@ -429,11 +429,20 @@ void * menu_write_w(uint32_t address, void * context, uint16_t value)
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;
}
diff --git a/serialize.c b/serialize.c
index 08ee7e8..dc54bb8 100644
--- a/serialize.c
+++ b/serialize.c
@@ -257,7 +257,6 @@ uint8_t load_from_file(deserialize_buffer *buf, char *path)
fclose(f);
return 0;
}
- fclose(f);
if (memcmp(ident, sz_ident, sizeof(ident))) {
return 0;
}
@@ -267,10 +266,12 @@ uint8_t load_from_file(deserialize_buffer *buf, char *path)
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;
}
diff --git a/vdp.c b/vdp.c
index 898facb..e86897d 100644
--- a/vdp.c
+++ b/vdp.c
@@ -774,7 +774,16 @@ static void read_sprite_x_mode4(vdp_context * context)
//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 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value)
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
diff --git a/vdp.h b/vdp.h
index a8285c1..6d43c74 100644
--- a/vdp.h
+++ b/vdp.h
@@ -244,7 +244,7 @@ void vdp_print_sprite_table(vdp_context * context);
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);