# HG changeset patch # User Michael Pavone # Date 1502346411 25200 # Node ID 2540c05520f2402c46f177daa076e227d7e98ef2 # Parent 4e5797b3935a701cb1e06d1871264ae39833669a 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 diff -r 4e5797b3935a -r 2540c05520f2 blastem.c --- 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) { diff -r 4e5797b3935a -r 2540c05520f2 blastem.h --- 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_ diff -r 4e5797b3935a -r 2540c05520f2 default.cfg --- 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 { diff -r 4e5797b3935a -r 2540c05520f2 genesis.c --- 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++) { diff -r 4e5797b3935a -r 2540c05520f2 genesis.h --- 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_ diff -r 4e5797b3935a -r 2540c05520f2 gst.c --- 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); diff -r 4e5797b3935a -r 2540c05520f2 menu.c --- 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; } diff -r 4e5797b3935a -r 2540c05520f2 serialize.c --- 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; } diff -r 4e5797b3935a -r 2540c05520f2 vdp.c --- 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 diff -r 4e5797b3935a -r 2540c05520f2 vdp.h --- 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);