diff genesis.c @ 1692:5dacaef602a7 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 05 Jan 2019 00:58:08 -0800
parents a763523dadf4 6909c5d0bbb5
children 3414a4423de1
line wrap: on
line diff
--- a/genesis.c	Tue Dec 19 00:49:13 2017 -0800
+++ b/genesis.c	Sat Jan 05 00:58:08 2019 -0800
@@ -16,6 +16,9 @@
 #include "util.h"
 #include "debug.h"
 #include "gdb_remote.h"
+#include "saves.h"
+#include "bindings.h"
+#include "jcart.h"
 #define MCLKS_NTSC 53693175
 #define MCLKS_PAL  53203395
 
@@ -29,7 +32,7 @@
 
 //TODO: Figure out the exact value for this
 #define LINES_NTSC 262
-#define LINES_PAL 312
+#define LINES_PAL 313
 
 #define MAX_SOUND_CYCLES 100000	
 
@@ -110,7 +113,7 @@
 
 static void update_z80_bank_pointer(genesis_context *gen)
 {
-	if (gen->z80->bank_reg < 0x100) {
+	if (gen->z80->bank_reg < 0x140) {
 		gen->z80->mem_pointers[1] = get_native_pointer(gen->z80->bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen);
 	} else {
 		gen->z80->mem_pointers[1] = NULL;
@@ -125,6 +128,7 @@
 	gen->z80->bank_reg = load_int16(buf) & 0x1FF;
 }
 
+static void adjust_int_cycle(m68k_context * context, vdp_context * v_context);
 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen)
 {
 	register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000);
@@ -144,6 +148,7 @@
 		load_section(buf);
 	}
 	update_z80_bank_pointer(gen);
+	adjust_int_cycle(gen->m68k, gen->vdp);
 }
 
 uint16_t read_dma_value(uint32_t address)
@@ -243,6 +248,7 @@
 	genesis_context * gen = z_context->system;
 	z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp);
 	z_context->int_pulse_end = z_context->int_pulse_start + Z80_INT_PULSE_MCLKS;
+	z_context->im2_vector = 0xFF;
 }
 
 static void sync_z80(z80_context * z_context, uint32_t mclks)
@@ -307,6 +313,11 @@
 	sync_z80(z_context, mclks);
 	sync_sound(gen, mclks);
 	vdp_run_context(v_context, mclks);
+	if (mclks >= gen->reset_cycle) {
+		gen->reset_requested = 1;
+		context->should_return = 1;
+		gen->reset_cycle = CYCLE_NEVER;
+	}
 	if (v_context->frame != last_frame_num) {
 		//printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", last_frame_num, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot);
 		last_frame_num = v_context->frame;
@@ -323,6 +334,9 @@
 			io_adjust_cycles(gen->io.ports, context->current_cycle, deduction);
 			io_adjust_cycles(gen->io.ports+1, context->current_cycle, deduction);
 			io_adjust_cycles(gen->io.ports+2, context->current_cycle, deduction);
+			if (gen->mapper_type == MAPPER_JCART) {
+				jcart_adjust_cycles(gen, deduction);
+			}
 			context->current_cycle -= deduction;
 			z80_adjust_cycles(z_context, deduction);
 			gen->ym->current_cycle -= deduction;
@@ -330,6 +344,9 @@
 			if (gen->ym->write_cycle != CYCLE_NEVER) {
 				gen->ym->write_cycle = gen->ym->write_cycle >= deduction ? gen->ym->write_cycle - deduction : 0;
 			}
+			if (gen->reset_cycle != CYCLE_NEVER) {
+				gen->reset_cycle -= deduction;
+			}
 		}
 	}
 	gen->frame_end = vdp_cycles_to_frame_end(v_context);
@@ -344,6 +361,9 @@
 		context->sync_cycle = context->current_cycle + 1;
 	}
 	adjust_int_cycle(context, v_context);
+	if (gen->reset_cycle < context->target_cycle) {
+		context->target_cycle = gen->reset_cycle;
+	}
 	if (address) {
 		if (gen->header.enter_debugger) {
 			gen->header.enter_debugger = 0;
@@ -359,18 +379,7 @@
 					sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
 				}
 			}
-			char *save_path;
-			if (slot == QUICK_SAVE_SLOT) {
-				save_path = save_state_path;
-			} else {
-				char slotname[] = "slot_0.state";
-				slotname[5] = '0' + slot;
-				if (!use_native_states) {
-					strcpy(slotname + 7, "gst");
-				}
-				char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname};
-				save_path = alloc_concat_m(3, parts);
-			}
+			char *save_path = get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst");
 			if (use_native_states) {
 				serialize_buffer state;
 				init_serialize(&state);
@@ -381,9 +390,7 @@
 				save_gst(gen, save_path, address);
 			}
 			printf("Saved state to %s\n", save_path);
-			if (slot != QUICK_SAVE_SLOT) {
-				free(save_path);
-			}
+			free(save_path);
 		} else if(gen->header.save_state) {
 			context->sync_cycle = context->current_cycle + 1;
 		}
@@ -1008,37 +1015,24 @@
 	gen->master_clock = gen->normal_clock;
 }
 
-static void handle_reset_requests(genesis_context *gen)
-{
-	while (gen->reset_requested)
-	{
-		gen->reset_requested = 0;
-		z80_assert_reset(gen->z80, gen->m68k->current_cycle);
-		z80_clear_busreq(gen->z80, gen->m68k->current_cycle);
-		ym_reset(gen->ym);
-		//Is there any sort of VDP reset?
-		m68k_reset(gen->m68k);
-	}
-	vdp_release_framebuffer(gen->vdp);
-}
-
 #include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up
 static uint8_t load_state(system_header *system, uint8_t slot)
 {
 	genesis_context *gen = (genesis_context *)system;
-	char numslotname[] = "slot_0.state";
-	char *slotname;
-	if (slot == QUICK_SAVE_SLOT) {
-		slotname = "quicksave.state";
-	} else {
-		numslotname[5] = '0' + slot;
-		slotname = numslotname;
-	}
-	char const *parts[] = {gen->header.save_dir, PATH_SEP, slotname};
-	char *statepath = alloc_concat_m(3, parts);
+	char *statepath = get_slot_name(system, slot, "state");
 	deserialize_buffer state;
 	uint32_t pc = 0;
 	uint8_t ret;
+	if (!gen->m68k->resume_pc) {
+		system->delayed_load_slot = slot + 1;
+		gen->m68k->should_return = 1;
+		ret = get_modification_time(statepath) != 0;
+		if (!ret) {
+			strcpy(statepath + strlen(statepath)-strlen("state"), "gst");
+			ret = get_modification_time(statepath) != 0;
+		}
+		goto done;
+	}
 	if (load_from_file(&state, statepath)) {
 		genesis_deserialize(&state, gen);
 		free(state.data);
@@ -1053,15 +1047,39 @@
 	if (ret) {
 		gen->m68k->resume_pc = get_native_address_trans(gen->m68k, pc);
 	}
+done:
 	free(statepath);
 	return ret;
 }
 
+static void handle_reset_requests(genesis_context *gen)
+{
+	while (gen->reset_requested || gen->header.delayed_load_slot)
+	{
+		if (gen->reset_requested) {
+			gen->reset_requested = 0;
+			gen->m68k->should_return = 0;
+			z80_assert_reset(gen->z80, gen->m68k->current_cycle);
+			z80_clear_busreq(gen->z80, gen->m68k->current_cycle);
+			ym_reset(gen->ym);
+			//Is there any sort of VDP reset?
+			m68k_reset(gen->m68k);
+		}
+		if (gen->header.delayed_load_slot) {
+			load_state(&gen->header, gen->header.delayed_load_slot - 1);
+			gen->header.delayed_load_slot = 0;
+			resume_68k(gen->m68k);
+		}
+	}
+	bindings_release_capture();
+	vdp_release_framebuffer(gen->vdp);
+	render_pause_source(gen->ym->audio);
+	render_pause_source(gen->psg->audio);
+}
+
 static void start_genesis(system_header *system, char *statefile)
 {
 	genesis_context *gen = (genesis_context *)system;
-	set_keybindings(&gen->io);
-	render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
 	if (statefile) {
 		//first try loading as a native format savestate
 		deserialize_buffer state;
@@ -1100,9 +1118,11 @@
 static void resume_genesis(system_header *system)
 {
 	genesis_context *gen = (genesis_context *)system;
-	map_all_bindings(&gen->io);
 	render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
+	bindings_reacquire_capture();
 	vdp_reacquire_framebuffer(gen->vdp);
+	render_resume_source(gen->ym->audio);
+	render_resume_source(gen->psg->audio);
 	resume_68k(gen->m68k);
 	handle_reset_requests(gen);
 }
@@ -1110,19 +1130,7 @@
 static void inc_debug_mode(system_header *system)
 {
 	genesis_context *gen = (genesis_context *)system;
-	gen->vdp->debug++;
-	if (gen->vdp->debug == 7) {
-		gen->vdp->debug = 0;
-	}
-}
-
-static void inc_debug_pal(system_header *system)
-{
-	genesis_context *gen = (genesis_context *)system;
-	gen->vdp->debug_pal++;
-	if (gen->vdp->debug_pal == 4) {
-		gen->vdp->debug_pal = 0;
-	}
+	vdp_inc_debug_mode(gen->vdp);
 }
 
 static void request_exit(system_header *system)
@@ -1163,14 +1171,20 @@
 static void soft_reset(system_header *system)
 {
 	genesis_context *gen = (genesis_context *)system;
-	gen->m68k->should_return = 1;
-	gen->reset_requested = 1;
+	if (gen->reset_cycle == CYCLE_NEVER) {
+		double random = (double)rand()/(double)RAND_MAX;
+		gen->reset_cycle = gen->m68k->current_cycle + random * MCLKS_LINE * (gen->version_reg & HZ50 ? LINES_PAL : LINES_NTSC);
+		if (gen->reset_cycle < gen->m68k->target_cycle) {
+			gen->m68k->target_cycle = gen->reset_cycle;
+		}
+	}
 }
 
 static void free_genesis(system_header *system)
 {
 	genesis_context *gen = (genesis_context *)system;
 	vdp_free(gen->vdp);
+	memmap_chunk *map = (memmap_chunk *)gen->m68k->options->gen.memmap;
 	m68k_options_free(gen->m68k->options);
 	free(gen->cart);
 	free(gen->m68k);
@@ -1180,12 +1194,72 @@
 	free(gen->zram);
 	ym_free(gen->ym);
 	psg_free(gen->psg);
-	free(gen->save_storage);
 	free(gen->header.save_dir);
+	free_rom_info(&gen->header.info);
 	free(gen->lock_on);
 	free(gen);
 }
 
+static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_gamepad_down(&gen->io, gamepad_num, button);
+	if (gen->mapper_type == MAPPER_JCART) {
+		jcart_gamepad_down(gen, gamepad_num, button);
+	}
+}
+
+static void gamepad_up(system_header *system, uint8_t gamepad_num, uint8_t button)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_gamepad_up(&gen->io, gamepad_num, button);
+	if (gen->mapper_type == MAPPER_JCART) {
+		jcart_gamepad_up(gen, gamepad_num, button);
+	}
+}
+
+static void mouse_down(system_header *system, uint8_t mouse_num, uint8_t button)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_mouse_down(&gen->io, mouse_num, button);
+}
+
+static void mouse_up(system_header *system, uint8_t mouse_num, uint8_t button)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_mouse_up(&gen->io, mouse_num, button);
+}
+
+static void mouse_motion_absolute(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_mouse_motion_absolute(&gen->io, mouse_num, x, y);
+}
+
+static void mouse_motion_relative(system_header *system, uint8_t mouse_num, int32_t x, int32_t y)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_mouse_motion_relative(&gen->io, mouse_num, x, y);
+}
+
+static void keyboard_down(system_header *system, uint8_t scancode)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_keyboard_down(&gen->io, scancode);
+}
+
+static void keyboard_up(system_header *system, uint8_t scancode)
+{
+	genesis_context *gen = (genesis_context *)system;
+	io_keyboard_up(&gen->io, scancode);
+}
+
+static void config_updated(system_header *system)
+{
+	genesis_context *gen = (genesis_context *)system;
+	setup_io_devices(config, &system->info, &gen->io);
+}
+
 static genesis_context *shared_init(uint32_t system_opts, rom_info *rom, uint8_t force_region)
 {
 	static memmap_chunk z80_map[] = {
@@ -1217,13 +1291,20 @@
 	gen->header.get_open_bus_value = get_open_bus_value;
 	gen->header.request_exit = request_exit;
 	gen->header.inc_debug_mode = inc_debug_mode;
-	gen->header.inc_debug_pal = inc_debug_pal;
+	gen->header.gamepad_down = gamepad_down;
+	gen->header.gamepad_up = gamepad_up;
+	gen->header.mouse_down = mouse_down;
+	gen->header.mouse_up = mouse_up;
+	gen->header.mouse_motion_absolute = mouse_motion_absolute;
+	gen->header.mouse_motion_relative = mouse_motion_relative;
+	gen->header.keyboard_down = keyboard_down;
+	gen->header.keyboard_up = keyboard_up;
+	gen->header.config_updated = config_updated;
 	gen->header.type = SYSTEM_GENESIS;
-	
+	gen->header.info = *rom;
 	set_region(gen, rom, force_region);
 	
-	gen->vdp = malloc(sizeof(vdp_context));
-	init_vdp_context(gen->vdp, gen->version_reg & 0x40);
+	gen->vdp = init_vdp_context(gen->version_reg & 0x40);
 	gen->vdp->system = &gen->header;
 	gen->frame_end = vdp_cycles_to_frame_end(gen->vdp);
 	char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval;
@@ -1231,16 +1312,14 @@
 	gen->int_latency_prev1 = MCLKS_PER_68K * 32;
 	gen->int_latency_prev2 = MCLKS_PER_68K * 16;
 	
-	char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval;
-	uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF;
+	render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC);
 	
 	gen->ym = malloc(sizeof(ym2612_context));
-	ym_init(gen->ym, render_sample_rate(), gen->master_clock, MCLKS_PER_YM, render_audio_buffer(), system_opts, lowpass_cutoff);
+	ym_init(gen->ym, gen->master_clock, MCLKS_PER_YM, system_opts);
 
 	gen->psg = malloc(sizeof(psg_context));
-	psg_init(gen->psg, render_sample_rate(), gen->master_clock, MCLKS_PER_PSG, render_audio_buffer(), lowpass_cutoff);
+	psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG);
 
-	gen->zram = calloc(1, Z80_RAM_BYTES);
 	z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES);
 #ifndef NO_Z80
 	z80_options *z_opts = malloc(sizeof(z80_options));
@@ -1298,6 +1377,7 @@
 	gen->lock_on = lock_on;
 	
 	setup_io_devices(config, rom, &gen->io);
+	gen->header.has_keyboard = io_has_keyboard(&gen->io);
 	gen->mapper_type = rom->mapper_type;
 	gen->save_type = rom->save_type;
 	if (gen->save_type != SAVE_NONE) {
@@ -1309,7 +1389,8 @@
 		if (gen->save_type == SAVE_I2C) {
 			eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size);
 		} else if (gen->save_type == SAVE_NOR) {
-			nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus);
+			memcpy(&gen->nor, rom->nor, sizeof(gen->nor));
+			//nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus);
 		}
 	} else {
 		gen->save_storage = NULL;
@@ -1363,32 +1444,43 @@
 };
 const size_t base_chunks = sizeof(base_map)/sizeof(*base_map); 
 
-genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out)
+genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region)
 {
 	tern_node *rom_db = get_rom_db();
-	*info_out = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks);
-	rom = info_out->rom;
-	rom_size = info_out->rom_size;
+	rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks);
+	rom = info.rom;
+	rom_size = info.rom_size;
 #ifndef BLASTEM_BIG_ENDIAN
 	byteswap_rom(rom_size, rom);
 	if (lock_on) {
 		byteswap_rom(lock_on_size, lock_on);
 	}
 #endif
-	return alloc_init_genesis(info_out, rom, lock_on, ym_opts, force_region);
+	char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval;
+	if (!m68k_divider) {
+		m68k_divider = "7";
+	}
+	MCLKS_PER_68K = atoi(m68k_divider);
+	if (!MCLKS_PER_68K) {
+		MCLKS_PER_68K = 7;
+	}
+	return alloc_init_genesis(&info, rom, lock_on, ym_opts, force_region);
 }
 
-genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region, rom_info *info_out)
+genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region)
 {
-	segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, info_out);
-	genesis_context *gen = shared_init(system_opts, info_out, force_region);
+	tern_node *rom_db = get_rom_db();
+	rom_info info = configure_rom(rom_db, media->buffer, media->size, NULL, 0, base_map, base_chunks);
+	
+	segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, &info);
+	genesis_context *gen = shared_init(system_opts, &info, force_region);
 	gen->cart = gen->lock_on = NULL;
 	gen->save_storage = NULL;
 	gen->save_type = SAVE_NONE;
 	gen->version_reg &= ~NO_DISK;
 	
 	gen->expansion = cd;
-	setup_io_devices(config, info_out, &gen->io);
+	setup_io_devices(config, &info, &gen->io);
 	
 	uint32_t cd_chunks;
 	memmap_chunk *cd_map = segacd_main_cpu_map(gen->expansion, &cd_chunks);