changeset 1444:14a2834d010c

Save/restore mapper state in native save states
author Michael Pavone <pavone@retrodev.com>
date Sun, 27 Aug 2017 18:15:00 -0700
parents 93c1b056ccdd
children 349d50930c03
files genesis.c genesis.h multi_game.c multi_game.h realtec.c realtec.h romdb.c romdb.h sega_mapper.c sega_mapper.h xband.c xband.h
diffstat 12 files changed, 157 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- 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;
--- 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;
--- 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);
+}
--- 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_
--- 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;
--- 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_
--- 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);
--- 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_
--- 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));
+	}
+}
--- 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_
--- 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;
--- 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 <stdint.h>
+#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_