diff segacd.c @ 2280:9ead0fe69d9b

Implement savestate support for Sega CD
author Michael Pavone <pavone@retrodev.com>
date Sun, 08 Jan 2023 14:42:24 -0800
parents 5a21bc0ec583
children b9fed07f19e4
line wrap: on
line diff
--- a/segacd.c	Sun Jan 08 14:20:43 2023 -0800
+++ b/segacd.c	Sun Jan 08 14:42:24 2023 -0800
@@ -7,6 +7,7 @@
 #include "debug.h"
 #include "gdb_remote.h"
 #include "blastem.h"
+#include "cdimage.h"
 
 #define SCD_MCLKS 50000000
 #define SCD_PERIPH_RESET_CLKS (SCD_MCLKS / 10)
@@ -1057,14 +1058,17 @@
 	context->current_cycle += num_refresh * REFRESH_DELAY;
 
 	scd_peripherals_run(cd, context->current_cycle);
-	if (address && cd->enter_debugger) {
-		genesis_context *gen = cd->genesis;
-		cd->enter_debugger = 0;
-		if (gen->header.debugger_type == DEBUGGER_NATIVE) {
-			debugger(context, address);
-		} else {
-			gdb_debug_enter(context, address);
+	if (address) {
+		if (cd->enter_debugger) {
+			genesis_context *gen = cd->genesis;
+			cd->enter_debugger = 0;
+			if (gen->header.debugger_type == DEBUGGER_NATIVE) {
+				debugger(context, address);
+			} else {
+				gdb_debug_enter(context, address);
+			}
 		}
+		cd->m68k_pc = address;
 	}
 	switch (context->int_ack)
 	{
@@ -1453,14 +1457,8 @@
 	memcpy(cd->rom_mut, cd->rom, adjusted_size);
 	cd->rom_mut[0x72/2] = 0xFFFF;
 
-	//memset(info, 0, sizeof(*info));
-	//tern_node *db = get_rom_db();
-	//*info = configure_rom(db, media->buffer, media->size, media->chain ? media->chain->buffer : NULL, media->chain ? media->chain->size : 0, NULL, 0);
-
 	cd->prog_ram = calloc(512*1024, 1);
 	cd->word_ram = calloc(256*1024, 1);
-	cd->pcm_ram = calloc(64*1024, 1);
-	//TODO: Load state from file
 	cd->bram = calloc(8*1024, 1);
 
 
@@ -1497,12 +1495,144 @@
 	m68k_options_free(cd->m68k->options);
 	free(cd->m68k);
 	free(cd->bram);
-	free(cd->pcm_ram);
 	free(cd->word_ram);
 	free(cd->prog_ram);
 	free(cd->rom_mut);
 }
 
+void segacd_serialize(segacd_context *cd, serialize_buffer *buf, uint8_t all)
+{
+	if (all) {
+		start_section(buf, SECTION_SUB_68000);
+		m68k_serialize(cd->m68k, cd->m68k_pc, buf);
+		end_section(buf);
+
+		start_section(buf, SECTION_GATE_ARRAY);
+		save_buffer16(buf, cd->gate_array, sizeof(cd->gate_array)/sizeof(*cd->gate_array));
+		save_buffer16(buf, cd->prog_ram, 256*1024);
+		save_buffer16(buf, cd->word_ram, 128*1024);
+		save_int16(buf, cd->rom_mut[0x72/2]);
+		save_int32(buf, cd->stopwatch_cycle);
+		save_int32(buf, cd->int2_cycle);
+		save_int32(buf, cd->graphics_int_cycle);
+		save_int32(buf, cd->periph_reset_cycle);
+		save_int32(buf, cd->last_refresh_cycle);
+		save_int32(buf, cd->graphics_cycle);
+		save_int32(buf, cd->base);
+		save_int32(buf, cd->graphics_x);
+		save_int32(buf, cd->graphics_y);
+		save_int32(buf, cd->graphics_dx);
+		save_int32(buf, cd->graphics_dy);
+		save_int32(buf, cd->graphics_dst_x);
+		save_buffer8(buf, cd->graphics_pixels, sizeof(cd->graphics_pixels));
+		save_int8(buf, cd->timer_pending);
+		save_int8(buf, cd->timer_value);
+		save_int8(buf, cd->busreq);
+		save_int8(buf, cd->reset);
+		save_int8(buf, cd->need_reset);
+		save_int8(buf, cd->cdc_dst_low);
+		save_int8(buf, cd->cdc_int_ack);
+		save_int8(buf, cd->graphics_step);
+		save_int8(buf, cd->graphics_dst_y);
+		save_int8(buf, cd->main_has_word2m);
+		save_int8(buf, cd->main_swap_request);
+		save_int8(buf, cd->bank_toggle);
+		save_int8(buf, cd->sub_paused_wordram);
+		end_section(buf);
+
+		start_section(buf, SECTION_CDD_MCU);
+		cdd_mcu_serialize(&cd->cdd, buf);
+		end_section(buf);
+
+		start_section(buf, SECTION_LC8951);
+		lc8951_serialize(&cd->cdc, buf);
+		end_section(buf);
+
+		start_section(buf, SECTION_CDROM);
+		cdimage_serialize(cd->cdd.media, buf);
+		end_section(buf);
+	}
+	start_section(buf, SECTION_RF5C164);
+	rf5c164_serialize(&cd->pcm, buf);
+	end_section(buf);
+
+	start_section(buf, SECTION_CDD_FADER);
+	cdd_fader_serialize(&cd->fader, buf);
+	end_section(buf);
+}
+
+static void gate_array_deserialize(deserialize_buffer *buf, void *vcd)
+{
+	segacd_context *cd = vcd;
+	load_buffer16(buf, cd->gate_array, sizeof(cd->gate_array)/sizeof(*cd->gate_array));
+	load_buffer16(buf, cd->prog_ram, 256*1024);
+	load_buffer16(buf, cd->word_ram, 128*1024);
+	cd->rom_mut[0x72/2] = load_int16(buf);
+	cd->stopwatch_cycle = load_int32(buf);
+	cd->int2_cycle = load_int32(buf);
+	cd->graphics_int_cycle = load_int32(buf);
+	cd->periph_reset_cycle = load_int32(buf);
+	cd->last_refresh_cycle = load_int32(buf);
+	cd->graphics_cycle = load_int32(buf);
+	cd->base = load_int32(buf);
+	cd->graphics_x = load_int32(buf);
+	cd->graphics_y = load_int32(buf);
+	cd->graphics_dx = load_int32(buf);
+	cd->graphics_dy = load_int32(buf);
+	cd->graphics_dst_x = load_int32(buf);
+	load_buffer8(buf, cd->graphics_pixels, sizeof(cd->graphics_pixels));
+	cd->timer_pending = load_int8(buf);
+	cd->timer_value = load_int8(buf);
+	cd->busreq = load_int8(buf);
+	cd->reset = load_int8(buf);
+	cd->need_reset = load_int8(buf);
+	cd->cdc_dst_low = load_int8(buf);
+	cd->cdc_int_ack = load_int8(buf);
+	cd->graphics_step = load_int8(buf);
+	cd->graphics_dst_y = load_int8(buf);
+	cd->main_has_word2m = load_int8(buf);
+	cd->main_swap_request = load_int8(buf);
+	cd->bank_toggle = load_int8(buf);
+	cd->sub_paused_wordram = load_int8(buf);
+
+	if (cd->gate_array[GA_MEM_MODE] & BIT_MEM_MODE) {
+		//1M mode
+		cd->genesis->m68k->mem_pointers[cd->memptr_start_index + 1] = NULL;
+		cd->genesis->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL;
+		cd->m68k->mem_pointers[0] = NULL;
+		cd->m68k->mem_pointers[1] = cd->bank_toggle ? cd->word_ram : cd->word_ram + 1;
+	} else {
+		//2M mode
+		if (cd->main_has_word2m) {
+			//main CPU has word ram
+			cd->genesis->m68k->mem_pointers[cd->memptr_start_index + 1] = cd->word_ram;
+			cd->genesis->m68k->mem_pointers[cd->memptr_start_index + 2] = cd->word_ram + 0x10000;
+			cd->m68k->mem_pointers[0] = NULL;
+			cd->m68k->mem_pointers[1] = NULL;
+		} else {
+			//sub cpu has word ram
+			cd->genesis->m68k->mem_pointers[cd->memptr_start_index + 1] = NULL;
+			cd->genesis->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL;
+			cd->m68k->mem_pointers[0] = cd->word_ram;
+			cd->m68k->mem_pointers[1] = NULL;
+		}
+	}
+
+	m68k_invalidate_code_range(cd->m68k, 0, 0x0E0000);
+	m68k_invalidate_code_range(cd->genesis->m68k, cd->base + 0x200000, cd->base + 0x240000);
+}
+
+void segacd_register_section_handlers(segacd_context *cd, deserialize_buffer *buf)
+{
+	register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = cd->m68k}, SECTION_SUB_68000);
+	register_section_handler(buf, (section_handler){.fun = gate_array_deserialize, .data = cd}, SECTION_GATE_ARRAY);
+	register_section_handler(buf, (section_handler){.fun = cdd_mcu_deserialize, .data = &cd->cdd}, SECTION_CDD_MCU);
+	register_section_handler(buf, (section_handler){.fun = lc8951_deserialize, .data = &cd->cdc}, SECTION_LC8951);
+	register_section_handler(buf, (section_handler){.fun = rf5c164_deserialize, .data = &cd->pcm}, SECTION_RF5C164);
+	register_section_handler(buf, (section_handler){.fun = cdd_fader_deserialize, .data = &cd->fader}, SECTION_CDD_FADER);
+	register_section_handler(buf, (section_handler){.fun = cdimage_deserialize, .data = cd->cdd.media}, SECTION_CDROM);
+}
+
 memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint8_t cart_boot, uint32_t *num_chunks)
 {
 	static memmap_chunk main_cpu_map[] = {