mirror of
https://github.com/libretro/blastem.git
synced 2026-11-07 10:15:58 -10:00
Save/restore mapper state in native save states
This commit is contained in:
1 parent
cae76760c6
commit
c96509a56b
12 files changed
+157
-8
No files matched your search
@@ -81,7 +81,7 @@ void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68
|
||||
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 @@ void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen)
|
||||
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 @@ genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -46,6 +46,7 @@ struct genesis_context {
|
||||
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;
|
||||
|
||||
@@ -4,6 +4,7 @@ void *write_multi_game_b(uint32_t address, void *vcontext, uint8_t value)
|
||||
{
|
||||
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 @@ void *write_multi_game_w(uint32_t address, void *context, uint16_t value)
|
||||
{
|
||||
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);
|
||||
}
|
||||
+3
-1
@@ -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_
|
||||
@@ -20,6 +20,14 @@ uint8_t realtec_detect(uint8_t *rom, uint32_t rom_size)
|
||||
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 @@ static void *realtec_write_b(uint32_t address, void *context, uint8_t value)
|
||||
}
|
||||
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 @@ static void *realtec_write_w(uint32_t address, void *context, uint16_t value)
|
||||
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 @@ rom_info realtec_configure_rom(uint8_t *rom, uint32_t rom_size, memmap_chunk con
|
||||
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;
|
||||
|
||||
@@ -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_
|
||||
@@ -58,6 +58,60 @@ void free_rom_info(rom_info *info)
|
||||
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 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk
|
||||
}
|
||||
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 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk
|
||||
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 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk
|
||||
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 @@ void map_iter_fun(char *key, tern_val val, uint8_t valtype, void *data)
|
||||
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 @@ void map_iter_fun(char *key, tern_val val, uint8_t valtype, void *data)
|
||||
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 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *l
|
||||
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);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define SAVE_NONE 0xFF
|
||||
|
||||
#include "tern.h"
|
||||
#include "serialize.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t start;
|
||||
@@ -37,6 +38,14 @@ typedef struct {
|
||||
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 @@ struct rom_info {
|
||||
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 @@ char const *save_type_name(uint8_t save_type);
|
||||
//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_
|
||||
@@ -133,3 +133,16 @@ m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_
|
||||
}
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -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_w(uint32_t address, m68k_context * context, uint1
|
||||
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_
|
||||
@@ -293,6 +293,25 @@ static uint16_t xband_reg_read_w(uint32_t address, void *context)
|
||||
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 @@ rom_info xband_configure_rom(tern_node *rom_db, void *rom, uint32_t rom_size, vo
|
||||
|
||||
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;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef XBAND_H_
|
||||
#define XBAND_H_
|
||||
#include <stdint.h>
|
||||
#include "serialize.h"
|
||||
|
||||
#define XBAND_REGS 0xE0
|
||||
|
||||
@@ -13,5 +14,7 @@ typedef struct {
|
||||
|
||||
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_
|
||||
Reference in new issue
Block a user