Mercurial > repos > blastem
diff genesis.c @ 1427:4e5797b3935a
WIP - New savestate format
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 06 Aug 2017 00:06:36 -0700 |
parents | 975b5b7eaa77 |
children | 2540c05520f2 |
line wrap: on
line diff
--- a/genesis.c Fri Jul 07 21:44:49 2017 -0700 +++ b/genesis.c Sun Aug 06 00:06:36 2017 -0700 @@ -32,6 +32,98 @@ #define MAX_SOUND_CYCLES 100000 +void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc) +{ + start_section(buf, SECTION_68000); + m68k_serialize(gen->m68k, m68k_pc, buf); + end_section(buf); + + start_section(buf, SECTION_Z80); + z80_serialize(gen->z80, buf); + end_section(buf); + + start_section(buf, SECTION_VDP); + vdp_serialize(gen->vdp, buf); + end_section(buf); + + start_section(buf, SECTION_YM2612); + ym_serialize(gen->ym, buf); + end_section(buf); + + start_section(buf, SECTION_PSG); + psg_serialize(gen->psg, buf); + end_section(buf); + + //TODO: bus arbiter state + + start_section(buf, SECTION_SEGA_IO_1); + io_serialize(gen->io.ports, buf); + end_section(buf); + + start_section(buf, SECTION_SEGA_IO_2); + io_serialize(gen->io.ports + 1, buf); + end_section(buf); + + start_section(buf, SECTION_SEGA_IO_EXT); + io_serialize(gen->io.ports + 2, buf); + end_section(buf); + + start_section(buf, SECTION_MAIN_RAM); + save_int8(buf, RAM_WORDS * 2 / 1024); + save_buffer16(buf, gen->work_ram, RAM_WORDS); + end_section(buf); + + start_section(buf, SECTION_SOUND_RAM); + save_int8(buf, Z80_RAM_BYTES / 1024); + save_buffer8(buf, gen->zram, Z80_RAM_BYTES); + end_section(buf); + + //TODO: mapper state +} + +static void ram_deserialize(deserialize_buffer *buf, void *vgen) +{ + genesis_context *gen = vgen; + uint32_t ram_size = load_int8(buf) * 1024 / 2; + if (ram_size > RAM_WORDS) { + fatal_error("State has a RAM size of %d bytes", ram_size * 2); + } + load_buffer16(buf, gen->work_ram, ram_size); +} + +static void zram_deserialize(deserialize_buffer *buf, void *vgen) +{ + genesis_context *gen = vgen; + uint32_t ram_size = load_int8(buf) * 1024; + if (ram_size > Z80_RAM_BYTES) { + fatal_error("State has a Z80 RAM size of %d bytes", ram_size); + } + load_buffer8(buf, gen->zram, ram_size); +} + +void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) +{ + register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); + register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80); + register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP); + register_section_handler(buf, (section_handler){.fun = ym_deserialize, .data = gen->ym}, SECTION_YM2612); + register_section_handler(buf, (section_handler){.fun = psg_deserialize, .data = gen->psg}, SECTION_PSG); + //TODO: bus arbiter + //HACK + gen->z80->reset = 0; + gen->z80->busreq = 0; + register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports}, SECTION_SEGA_IO_1); + register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2); + register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT); + register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); + register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); + //TODO: mapper state + while (buf->cur_pos < buf->size) + { + load_section(buf); + } +} + uint16_t read_dma_value(uint32_t address) { genesis_context *genesis = (genesis_context *)current_system; @@ -252,7 +344,14 @@ char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname}; save_path = alloc_concat_m(3, parts); } - save_gst(gen, save_path, address); + 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); printf("Saved state to %s\n", save_path); if (slot != QUICK_SAVE_SLOT) { free(save_path); @@ -906,9 +1005,26 @@ 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) { - fatal_error("Failed to load save state %s\n", statefile); + //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); + genesis_deserialize(&state, gen); + free(statedata); + //HACK + pc = gen->m68k->last_prefetch_address; } printf("Loaded %s\n", statefile); if (gen->header.enter_debugger) { @@ -926,6 +1042,9 @@ m68k_reset(gen->m68k); } handle_reset_requests(gen); + return; +state_error: + fatal_error("Failed to load save state %s\n", statefile); } static void resume_genesis(system_header *system)