changeset 1503:a763523dadf4 segacd

Added code for initializing a combined Genesis + Sega CD system when a Sega CD ISO is loaded
author Michael Pavone <pavone@retrodev.com>
date Wed, 13 Dec 2017 09:44:41 -0800
parents 2564b6ba2e12
children 95b3a1a8b26c
files genesis.c genesis.h romdb.c romdb.h segacd.c segacd.h system.c
diffstat 7 files changed, 106 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/genesis.c	Tue Dec 12 09:44:33 2017 -0800
+++ b/genesis.c	Wed Dec 13 09:44:41 2017 -0800
@@ -4,6 +4,7 @@
  BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
 */
 #include "genesis.h"
+#include "segacd.h"
 #include "blastem.h"
 #include "nor.h"
 #include <stdlib.h>
@@ -1086,7 +1087,8 @@
 	} else {
 		if (gen->header.enter_debugger) {
 			gen->header.enter_debugger = 0;
-			uint32_t address = gen->cart[2] << 16 | gen->cart[3];
+			uint32_t address = read_word(4, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k) << 16
+				| read_word(6, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k);
 			insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter);
 		}
 		m68k_reset(gen->m68k);
@@ -1184,7 +1186,7 @@
 	free(gen);
 }
 
-genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region)
+static genesis_context *shared_init(uint32_t system_opts, rom_info *rom, uint8_t force_region)
 {
 	static memmap_chunk z80_map[] = {
 		{ 0x0000, 0x4000,  0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL,              NULL },
@@ -1193,6 +1195,16 @@
 		{ 0x6000, 0x6100,  0xFFFF, 0, 0, 0,                                  NULL, NULL, NULL, NULL,              z80_write_bank_reg},
 		{ 0x7F00, 0x8000,  0x00FF, 0, 0, 0,                                  NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
 	};
+	
+	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;
+	}
+	
 	genesis_context *gen = calloc(1, sizeof(genesis_context));
 	gen->header.set_speed_percent = set_speed_percent;
 	gen->header.start_context = start_genesis;
@@ -1207,8 +1219,9 @@
 	gen->header.inc_debug_mode = inc_debug_mode;
 	gen->header.inc_debug_pal = inc_debug_pal;
 	gen->header.type = SYSTEM_GENESIS;
+	
 	set_region(gen, rom, force_region);
-
+	
 	gen->vdp = malloc(sizeof(vdp_context));
 	init_vdp_context(gen->vdp, gen->version_reg & 0x40);
 	gen->vdp->system = &gen->header;
@@ -1217,7 +1230,7 @@
 	gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL;
 	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;
 	
@@ -1241,10 +1254,8 @@
 
 	gen->z80->system = gen;
 	gen->z80->mem_pointers[0] = gen->zram;
-	gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom;
-
-	gen->cart = main_rom;
-	gen->lock_on = lock_on;
+	gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = NULL;
+	
 	gen->work_ram = calloc(2, RAM_WORDS);
 	if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval))
 	{
@@ -1274,8 +1285,19 @@
 			gen->vdp->vsram[i] = rand();
 		}
 	}
+	
+	return gen;
+}
+
+genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region)
+{
+	genesis_context *gen = shared_init(system_opts, rom, force_region);
+	gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom;
+
+	gen->cart = main_rom;
+	gen->lock_on = lock_on;
+	
 	setup_io_devices(config, rom, &gen->io);
-
 	gen->mapper_type = rom->mapper_type;
 	gen->save_type = rom->save_type;
 	if (gen->save_type != SAVE_NONE) {
@@ -1329,23 +1351,22 @@
 	return gen;
 }
 
+static memmap_chunk base_map[] = {
+	{0xE00000, 0x1000000, 0xFFFF,   0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL,
+			   NULL,          NULL,         NULL,            NULL},
+	{0xC00000, 0xE00000,  0x1FFFFF, 0, 0, 0,                                  NULL,
+			   (read_16_fun)vdp_port_read,  (write_16_fun)vdp_port_write,
+			   (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
+	{0xA00000, 0xA12000,  0x1FFFF,  0, 0, 0,                                  NULL,
+			   (read_16_fun)io_read_w,      (write_16_fun)io_write_w,
+			   (read_8_fun)io_read,         (write_8_fun)io_write}
+};
+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)
 {
-	static memmap_chunk base_map[] = {
-		{0xE00000, 0x1000000, 0xFFFF,   0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL,
-		           NULL,          NULL,         NULL,            NULL},
-		{0xC00000, 0xE00000,  0x1FFFFF, 0, 0, 0,                                  NULL,
-		           (read_16_fun)vdp_port_read,  (write_16_fun)vdp_port_write,
-		           (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
-		{0xA00000, 0xA12000,  0x1FFFF,  0, 0, 0,                                  NULL,
-		           (read_16_fun)io_read_w,      (write_16_fun)io_write_w,
-		           (read_8_fun)io_read,         (write_8_fun)io_write}
-	};
-	static tern_node *rom_db;
-	if (!rom_db) {
-		rom_db = load_rom_db();
-	}
-	*info_out = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
+	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;
 #ifndef BLASTEM_BIG_ENDIAN
@@ -1354,13 +1375,43 @@
 		byteswap_rom(lock_on_size, lock_on);
 	}
 #endif
-	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_out, 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)
+{
+	segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, info_out);
+	genesis_context *gen = shared_init(system_opts, info_out, 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);
+	
+	uint32_t cd_chunks;
+	memmap_chunk *cd_map = segacd_main_cpu_map(gen->expansion, &cd_chunks);
+	memmap_chunk *map = malloc(sizeof(memmap_chunk) * (cd_chunks + base_chunks));
+	memcpy(map, cd_map, sizeof(memmap_chunk) * cd_chunks);
+	memcpy(map + cd_chunks, base_map, sizeof(memmap_chunk) * base_chunks);
+	map[cd_chunks].buffer = gen->work_ram;
+	uint32_t num_chunks = cd_chunks + base_chunks;
+	
+	m68k_options *opts = malloc(sizeof(m68k_options));
+	init_m68k_opts(opts, map, num_chunks, MCLKS_PER_68K);
+	//TODO: make this configurable
+	opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY;
+	gen->m68k = init_68k_context(opts, NULL);
+	gen->m68k->system = gen;
+	opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL;
+	
+	//This must happen after the 68K context has been allocated
+	for (int i = 0; i < num_chunks; i++)
+	{
+		if (map[i].flags & MMAP_PTR_IDX) {
+			gen->m68k->mem_pointers[map[i].ptr_index] = map[i].buffer;
+		}
+	}
+	return gen;
+}
--- a/genesis.h	Tue Dec 12 09:44:33 2017 -0800
+++ b/genesis.h	Wed Dec 13 09:44:41 2017 -0800
@@ -63,6 +63,7 @@
 uint16_t read_dma_value(uint32_t address);
 m68k_context * sync_components(m68k_context *context, uint32_t address);
 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t system_opts, uint8_t force_region, rom_info *info_out);
+genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info_out);
 void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc);
 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen);
 
--- a/romdb.c	Tue Dec 12 09:44:33 2017 -0800
+++ b/romdb.c	Wed Dec 13 09:44:41 2017 -0800
@@ -33,11 +33,14 @@
 	return "SRAM";
 }
 
-tern_node *load_rom_db()
+tern_node *get_rom_db()
 {
-	tern_node *db = parse_bundled_config("rom.db");
+	static tern_node *db;
 	if (!db) {
-		fatal_error("Failed to load ROM DB\n");
+		db = parse_bundled_config("rom.db");
+		if (!db) {
+			fatal_error("Failed to load ROM DB\n");
+		}
 	}
 	return db;
 }
--- a/romdb.h	Tue Dec 12 09:44:33 2017 -0800
+++ b/romdb.h	Wed Dec 13 09:44:41 2017 -0800
@@ -79,7 +79,7 @@
 #define GAME_ID_OFF 0x183
 #define GAME_ID_LEN 8
 
-tern_node *load_rom_db();
+tern_node *get_rom_db();
 rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks);
 rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks);
 uint8_t translate_region_char(uint8_t c);
--- a/segacd.c	Tue Dec 12 09:44:33 2017 -0800
+++ b/segacd.c	Wed Dec 13 09:44:41 2017 -0800
@@ -203,6 +203,7 @@
 		{0xFF0000, 0xFF7FFF, 0x0000, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8},
 		{0xFF8000, 0xFF81FF, 0x0000, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8}
 	};
+	memset(info, 0, sizeof(*info));
 	segacd_context *cd = calloc(sizeof(segacd_context), 1);
 	FILE *f = fopen("cdbios.bin", "rb");
 	if (!f) {
@@ -215,8 +216,12 @@
 		fatal_error("Failed to read CD firmware");
 	}
 	cd->rom_mut = malloc(adjusted_size);
+	byteswap_rom(adjusted_size, cd->rom);
 	memcpy(cd->rom_mut, cd->rom, adjusted_size);
-	byteswap_rom(firmware_size, cd->rom);
+	
+	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 = malloc(512*1024);
 	cd->work_ram = malloc(256*1024);
 	cd->pcm_ram = malloc(64*1024);
@@ -238,7 +243,7 @@
 memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks)
 {
 	static memmap_chunk main_cpu_map[] = {
-		{0x000000, 0x01FFFF, 0x00000, .flags=MMAP_READ},
+		{0x000000, 0x01FFFF, 0xFFFFFF, .flags=MMAP_READ},
 		{0x020000, 0x03FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 0},//TODO: support running main CPU code from here
 		{0x040000, 0x05FFFF, 0x1FFFF, .flags=MMAP_READ}, //first ROM alias
 		//TODO: additional ROM/prog RAM aliases
--- a/segacd.h	Tue Dec 12 09:44:33 2017 -0800
+++ b/segacd.h	Wed Dec 13 09:44:41 2017 -0800
@@ -20,5 +20,6 @@
 } segacd_context;
 
 segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info);
+memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks);
 
 #endif //SEGACD_H_
--- a/system.c	Tue Dec 12 09:44:33 2017 -0800
+++ b/system.c	Wed Dec 13 09:44:41 2017 -0800
@@ -12,7 +12,11 @@
 system_type detect_system_type(system_media *media)
 {
 	if (safe_cmp("SEGA", 0x100, media->buffer, media->size)) {
-		//TODO: Differentiate between vanilla Genesis and Sega CD/32X games
+		//TODO: support other bootable identifiers
+		if (safe_cmp("SEGADISCSYSTEM", 0, media->buffer, media->size)) {
+			return SYSTEM_SEGACD;
+		}
+		//TODO: Differentiate between vanilla Genesis and 32X games
 		return SYSTEM_GENESIS;
 	}
 	if (safe_cmp("TMR SEGA", 0x1FF0, media->buffer, media->size)
@@ -60,6 +64,8 @@
 	{
 	case SYSTEM_GENESIS:
 		return &(alloc_config_genesis(media->buffer, media->size, lock_on, lock_on_size, opts, force_region, info_out))->header;
+	case SYSTEM_SEGACD:
+		return &(alloc_config_genesis_cdboot(media, opts, force_region, info_out))->header;
 #ifndef NO_Z80
 	case SYSTEM_SMS:
 		return &(alloc_configure_sms(media, opts, force_region, info_out))->header;