# HG changeset patch # User Michael Pavone # Date 1503882900 25200 # Node ID 14a2834d010cb83944bc4a9e77d424260de52636 # Parent 93c1b056ccdd8986f75643c5ca8b579efd0892c9 Save/restore mapper state in native save states diff -r 93c1b056ccdd -r 14a2834d010c genesis.c --- a/genesis.c Sat Aug 26 11:29:46 2017 -0700 +++ b/genesis.c Sun Aug 27 18:15:00 2017 -0700 @@ -81,7 +81,7 @@ save_buffer8(buf, gen->zram, Z80_RAM_BYTES); end_section(buf); - //TODO: mapper state + cart_serialize(&gen->header, buf); } static void ram_deserialize(deserialize_buffer *buf, void *vgen) @@ -124,6 +124,7 @@ 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); + register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); //TODO: mapper state while (buf->cur_pos < buf->size) { @@ -1267,7 +1268,7 @@ } setup_io_devices(config, rom, &gen->io); - gen->save_type = rom->save_type; + gen->mapper_type = rom->mapper_type; gen->save_type = rom->save_type; if (gen->save_type != SAVE_NONE) { gen->save_ram_mask = rom->save_mask; diff -r 93c1b056ccdd -r 14a2834d010c genesis.h --- a/genesis.h Sat Aug 26 11:29:46 2017 -0700 +++ b/genesis.h Sun Aug 27 18:15:00 2017 -0700 @@ -46,6 +46,7 @@ uint32_t int_latency_prev2; uint8_t bank_regs[8]; uint16_t mapper_start_index; + uint8_t mapper_type; uint8_t save_type; sega_io io; uint8_t version_reg; diff -r 93c1b056ccdd -r 14a2834d010c multi_game.c --- a/multi_game.c Sat Aug 26 11:29:46 2017 -0700 +++ b/multi_game.c Sun Aug 27 18:15:00 2017 -0700 @@ -4,6 +4,7 @@ { m68k_context *context = vcontext; genesis_context *gen = context->system; + gen->bank_regs[0] = address; uint32_t base = (address & 0x3F) << 16, start = 0, end = 0x400000; //find the memmap chunk, so we can properly mask the base value for (int i = 0; i < context->options->gen.memmap_chunks; i++) @@ -24,3 +25,13 @@ { return write_multi_game_b(address, context, value); } + +void multi_game_serialize(genesis_context *gen, serialize_buffer *buf) +{ + save_int8(buf, gen->bank_regs[0]); +} + +void multi_game_deserialize(deserialize_buffer *buf, genesis_context *gen) +{ + write_multi_game_b(load_int8(buf), gen, 0); +} diff -r 93c1b056ccdd -r 14a2834d010c multi_game.h --- a/multi_game.h Sat Aug 26 11:29:46 2017 -0700 +++ b/multi_game.h Sun Aug 27 18:15:00 2017 -0700 @@ -1,7 +1,9 @@ #ifndef MULTI_GAME_H_ #define MULTI_GAME_H_ +#include "serialize.h" void *write_multi_game_b(uint32_t address, void *context, uint8_t value); void *write_multi_game_w(uint32_t address, void *context, uint16_t value); - +void multi_game_serialize(genesis_context *gen, serialize_buffer *buf); +void multi_game_deserialize(deserialize_buffer *buf, genesis_context *gen); #endif //MULTI_GAME_H_ diff -r 93c1b056ccdd -r 14a2834d010c realtec.c --- a/realtec.c Sat Aug 26 11:29:46 2017 -0700 +++ b/realtec.c Sun Aug 27 18:15:00 2017 -0700 @@ -20,6 +20,14 @@ return memcmp(rom + 0x7E100, "SEGA", 4) == 0; } +static realtec *get_realtec(genesis_context *gen) +{ + if (!gen->extra) { + gen->extra = gen->m68k->mem_pointers[0]; + } + return gen->extra; +} + static void *realtec_write_b(uint32_t address, void *context, uint8_t value) { if (address & 1) { @@ -27,12 +35,8 @@ } m68k_context *m68k = context; genesis_context *gen = m68k->system; - if (!gen->extra) { - gen->extra = m68k->mem_pointers[0]; - } - realtec *r = gen->extra; + realtec *r = get_realtec(gen); uint32_t offset = address >> 13; - uint8_t dirty = 0; if (offset < 3 && r->regs[offset] != value) { r->regs[offset] = value; //other regs are only 3 bits, so assume 3 for this one too @@ -61,6 +65,21 @@ return realtec_write_b(address, context, value >> 8); } +void realtec_serialize(genesis_context *gen, serialize_buffer *buf) +{ + realtec *r = get_realtec(gen); + save_buffer8(buf, r->regs, sizeof(r->regs)); +} + +void realtec_deserialize(deserialize_buffer *buf, genesis_context *gen) +{ + realtec *r = get_realtec(gen); + for (int i = 0; i < sizeof(r->regs); i++) + { + realtec_write_b(i << 13, gen, load_int8(buf)); + } +} + rom_info realtec_configure_rom(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) { rom_info info; @@ -104,6 +123,7 @@ info.eeprom_map = NULL; info.rom = rom; info.rom_size = rom_size; + info.mapper_type = MAPPER_REALTEC; info.is_save_lock_on = 0; info.port1_override = info.port2_override = info.ext_override = info.mouse_mode = NULL; info.map_chunks = base_chunks + 2; diff -r 93c1b056ccdd -r 14a2834d010c realtec.h --- a/realtec.h Sat Aug 26 11:29:46 2017 -0700 +++ b/realtec.h Sun Aug 27 18:15:00 2017 -0700 @@ -1,7 +1,10 @@ #ifndef REALTEC_H_ #define REALTEC_H_ +#include "serialize.h" uint8_t realtec_detect(uint8_t *rom, uint32_t rom_size); rom_info realtec_configure_rom(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); +void realtec_serialize(genesis_context *gen, serialize_buffer *buf); +void realtec_deserialize(deserialize_buffer *buf, genesis_context *gen); #endif //REALTEC_H_ diff -r 93c1b056ccdd -r 14a2834d010c romdb.c --- a/romdb.c Sat Aug 26 11:29:46 2017 -0700 +++ b/romdb.c Sun Aug 27 18:15:00 2017 -0700 @@ -58,6 +58,60 @@ free(info->mouse_mode); } +void cart_serialize(system_header *sys, serialize_buffer *buf) +{ + if (sys->type != SYSTEM_GENESIS) { + return; + } + genesis_context *gen = (genesis_context *)sys; + if (gen->mapper_type == MAPPER_NONE) { + return; + } + start_section(buf, SECTION_MAPPER); + save_int8(buf, gen->mapper_type); + switch(gen->mapper_type) + { + case MAPPER_SEGA: + sega_mapper_serialize(gen, buf); + break; + case MAPPER_REALTEC: + realtec_serialize(gen, buf); + break; + case MAPPER_XBAND: + xband_serialize(gen, buf); + break; + case MAPPER_MULTI_GAME: + multi_game_serialize(gen, buf); + break; + } + end_section(buf); +} + +void cart_deserialize(deserialize_buffer *buf, void *vcontext) +{ + genesis_context *gen = vcontext; + uint8_t mapper_type = load_int8(buf); + if (mapper_type != gen->mapper_type) { + warning("Mapper type mismatch, skipping load of mapper state"); + return; + } + switch(gen->mapper_type) + { + case MAPPER_SEGA: + sega_mapper_deserialize(buf, gen); + break; + case MAPPER_REALTEC: + realtec_deserialize(buf, gen); + break; + case MAPPER_XBAND: + xband_deserialize(buf, gen); + break; + case MAPPER_MULTI_GAME: + multi_game_deserialize(buf, gen); + break; + } +} + char *get_header_name(uint8_t *rom) { //TODO: Should probably prefer the title field that corresponds to the user's region preference @@ -197,6 +251,7 @@ } if (size >= 0x80000 && !memcmp("SEGA SSF", rom + 0x100, 8)) { info->mapper_start_index = 0; + info->mapper_type = MAPPER_SEGA; info->map_chunks = base_chunks + 9; info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); memset(info->map, 0, sizeof(memmap_chunk)*9); @@ -265,6 +320,7 @@ info->map[1].buffer = info->save_buffer; } else { //Assume the standard Sega mapper + info->mapper_type = MAPPER_SEGA; info->map[0].end = 0x200000; info->map[0].mask = 0xFFFFFF; info->map[0].flags = MMAP_READ; @@ -308,6 +364,7 @@ rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) { rom_info info; + info.mapper_type = MAPPER_NONE; info.name = get_header_name(rom); info.regions = get_header_regions(rom); info.is_save_lock_on = 0; @@ -607,6 +664,7 @@ map->read_8 = nor_flash_read_b; map->mask = 0xFFFFFF; } else if (!strcmp(dtype, "Sega mapper")) { + state->info->mapper_type = MAPPER_SEGA; state->info->mapper_start_index = state->ptr_index++; char *variant = tern_find_ptr_default(node, "variant", "full"); char *save_device = tern_find_path(node, "save\0device\0", TVAL_PTR).ptrval; @@ -694,6 +752,7 @@ map->flags = MMAP_READ; *value = strtol(tern_find_ptr_default(node, "value", "0"), NULL, 16); } else if (!strcmp(dtype, "multi-game")) { + state->info->mapper_type = MAPPER_MULTI_GAME; state->info->mapper_start_index = state->ptr_index++; //make a mirror copy of the ROM so we can efficiently support arbitrary start offsets state->rom = realloc(state->rom, state->rom_size * 2); @@ -756,6 +815,7 @@ return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); } rom_info info; + info.mapper_type = MAPPER_NONE; info.name = tern_find_ptr(entry, "name"); if (info.name) { printf("Found name: %s\n", info.name); diff -r 93c1b056ccdd -r 14a2834d010c romdb.h --- a/romdb.h Sat Aug 26 11:29:46 2017 -0700 +++ b/romdb.h Sun Aug 27 18:15:00 2017 -0700 @@ -14,6 +14,7 @@ #define SAVE_NONE 0xFF #include "tern.h" +#include "serialize.h" typedef struct { uint32_t start; @@ -37,6 +38,14 @@ uint8_t bus_flags; } nor_state; +enum { + MAPPER_NONE, + MAPPER_SEGA, + MAPPER_REALTEC, + MAPPER_XBAND, + MAPPER_MULTI_GAME +}; + typedef struct rom_info rom_info; @@ -62,6 +71,7 @@ uint16_t mapper_start_index; uint8_t save_type; uint8_t save_bus; //only used for NOR currently + uint8_t mapper_type; uint8_t regions; uint8_t is_save_lock_on; //Does the save buffer actually belong to a lock-on cart? }; @@ -77,5 +87,7 @@ //Note: free_rom_info only frees things pointed to by a rom_info struct, not the struct itself //this is because rom_info structs are typically stack allocated void free_rom_info(rom_info *info); +void cart_serialize(system_header *sys, serialize_buffer *buf); +void cart_deserialize(deserialize_buffer *buf, void *vcontext); #endif //ROMDB_H_ diff -r 93c1b056ccdd -r 14a2834d010c sega_mapper.c --- a/sega_mapper.c Sat Aug 26 11:29:46 2017 -0700 +++ b/sega_mapper.c Sun Aug 27 18:15:00 2017 -0700 @@ -133,3 +133,16 @@ } return context; } + +void sega_mapper_serialize(genesis_context *gen, serialize_buffer *buf) +{ + save_buffer8(buf, gen->bank_regs, sizeof(gen->bank_regs)); +} + +void sega_mapper_deserialize(deserialize_buffer *buf, genesis_context *gen) +{ + for (int i = 0; i < sizeof(gen->bank_regs); i++) + { + write_bank_reg_w(i * 2, gen->m68k, load_int8(buf)); + } +} diff -r 93c1b056ccdd -r 14a2834d010c sega_mapper.h --- a/sega_mapper.h Sat Aug 26 11:29:46 2017 -0700 +++ b/sega_mapper.h Sun Aug 27 18:15:00 2017 -0700 @@ -1,5 +1,6 @@ #ifndef SEGA_MAPPER_H_ #define SEGA_MAPPER_H_ +#include "serialize.h" uint16_t read_sram_w(uint32_t address, m68k_context * context); uint8_t read_sram_b(uint32_t address, m68k_context * context); @@ -7,5 +8,7 @@ m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value); m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value); m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value); +void sega_mapper_serialize(genesis_context *gen, serialize_buffer *buf); +void sega_mapper_deserialize(deserialize_buffer *buf, genesis_context *gen); #endif //SEGA_MAPPER_H_ diff -r 93c1b056ccdd -r 14a2834d010c xband.c --- a/xband.c Sat Aug 26 11:29:46 2017 -0700 +++ b/xband.c Sun Aug 27 18:15:00 2017 -0700 @@ -293,6 +293,25 @@ return value; } +void xband_serialize(genesis_context *gen, serialize_buffer *buf) +{ + xband *x = get_xband(gen); + save_int8(buf, x->kill); + save_int8(buf, x->control); + save_buffer8(buf, x->regs, XBAND_REGS); +} + +void xband_deserialize(deserialize_buffer *buf, genesis_context *gen) +{ + xband *x = get_xband(gen); + x->kill = load_int8(buf); + update_control(gen, load_int8(buf)); + for (int i = 0; i < XBAND_REGS; i++) + { + xband_write_b(0x3BC001 + i*2, gen, load_int8(buf)); + } +} + rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks) { rom_info info; @@ -334,6 +353,7 @@ byteswap_rom(0x400000, x->cart_space); + info.mapper_type = MAPPER_XBAND; info.map_chunks = base_chunks + 5; info.map = calloc(sizeof(memmap_chunk), info.map_chunks); info.map[0].mask = 0xFFFFFF; diff -r 93c1b056ccdd -r 14a2834d010c xband.h --- a/xband.h Sat Aug 26 11:29:46 2017 -0700 +++ b/xband.h Sun Aug 27 18:15:00 2017 -0700 @@ -1,6 +1,7 @@ #ifndef XBAND_H_ #define XBAND_H_ #include +#include "serialize.h" #define XBAND_REGS 0xE0 @@ -13,5 +14,7 @@ uint8_t xband_detect(uint8_t *rom, uint32_t rom_size); rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks); +void xband_serialize(genesis_context *gen, serialize_buffer *buf); +void xband_deserialize(deserialize_buffer *buf, genesis_context *gen); #endif //XBAND_H_